Karakter grep sebelum dan sesudah pertandingan?

149

Menggunakan ini:

grep -A1 -B1 "test_pattern" file

akan menghasilkan satu baris sebelum dan sesudah pola yang cocok dalam file. Apakah ada cara untuk menampilkan bukan garis tetapi sejumlah karakter tertentu?

Garis-garis di file saya cukup besar jadi saya tidak tertarik untuk mencetak seluruh baris tetapi hanya mengamati kecocokan dalam konteks. Ada saran tentang cara untuk melakukan hal ini?

Legenda
sumber
1
Duplikat unix.stackexchange.com/q/163726 Dekat duplikat stackoverflow.com/q/2034799
sondra.kinsey

Jawaban:

190

3 karakter sebelum dan 4 karakter setelah

$> echo "some123_string_and_another" | grep -o -P '.{0,3}string.{0,4}'
23_string_and
ДМИТРИЙ МАЛИКОВ
sumber
5
Jawaban yang bagus untuk sejumlah kecil data, tetapi mulai menjadi lambat saat Anda mencocokkan> 100 karakter - misalnya dalam file xml raksasa saya, saya ingin {1.200} sebelum dan sesudah, dan terlalu lambat untuk digunakan.
Benubird
3
Versi awk oleh @amit_g jauh lebih cepat.
ssobczak
6
Tidak tersedia di Mac OSX, jadi ini bukan solusi yang tersedia secara luas. Versi -E (tercantum di bawah) adalah solusi yang lebih baik. Apa itu -P? Baca terus ... -P, --perl-regexp Tafsirkan POLA sebagai ekspresi reguler Perl (PCRE, lihat di bawah). Ini sangat eksperimental dan grep -P mungkin memperingatkan fitur yang tidak diterapkan.
Xofo
2
Di OSX, instal melalui: brew install homebrew/dupes/grepdan jalankan sebagai ggrep.
kenorb
1
Seperti yang tersirat oleh @Benubird, ini akan menjadi kinerja yang tidak mungkin digunakan untuk file besar dengan lingkungan yang cukup luas yang diinginkan untuk target pertandingan.
matanster
118
grep -E -o ".{0,5}test_pattern.{0,5}" test.txt 

Ini akan mencocokkan hingga 5 karakter sebelum dan sesudah pola Anda. Tombol -o memberi tahu grep untuk hanya menampilkan pertandingan dan -E untuk menggunakan ekspresi reguler yang diperluas. Pastikan untuk meletakkan tanda kutip di sekitar ekspresi Anda, jika tidak, itu mungkin ditafsirkan oleh shell.

ekse
sumber
1
Jawaban bagus, menarik karena dibatasi pada 2 ^ 8-1 untuk panjangnya {} jadi {0,255}karya {0,256}memberigrep: invalid repetition count(s)
CodeMonkey
1
Ini tampaknya menjadi sangat kurang berkinerja karena saya meningkatkan jumlah karakter yang cocok (5 -> 25 -> 50), tahu mengapa?
Adam Hughes
38

Anda bisa menggunakan

awk '/test_pattern/ {
    match($0, /test_pattern/); print substr($0, RSTART - 10, RLENGTH + 20);
}' file
amit_g
sumber
2
Bekerja dengan baik bahkan dengan file yang lebih besar juga
Touko
4
bagaimana Anda bisa menggunakan ini untuk menemukan beberapa kecocokan per baris?
koox00
1
Apa pentingnya angka pertama dalam pasangan kurung kurawal? Seperti angka 0 dalam "grep -E -o". {0,5} test_pattern. {0,5} "test.txt"?
Lew Rockwell Fan
Ini benar-benar lebih cepat tetapi tidak seakurat jawaban @ekse.
Abdollah
25

Maksud Anda, seperti ini:

grep -o '.\{0,20\}test_pattern.\{0,20\}' file

?

Itu akan mencetak hingga dua puluh karakter di kedua sisi test_pattern. The \{0,20\}notasi seperti *, tapi menspesifikasikan nol sampai dua puluh pengulangan bukan nol atau more.The -omengatakan untuk hanya menampilkan pertandingan itu sendiri, bukan seluruh baris.

ruakh
sumber
Perintah ini tidak berfungsi untuk saya:grep: Invalid content of \{\}
Alexander Pravdin
1

Saya tidak akan pernah dengan mudah mengingat pengubah perintah samar ini jadi saya mengambil jawaban teratas dan mengubahnya menjadi fungsi di ~/.bashrcfile saya :


cgrep() {
    # For files that are arrays 10's of thousands of characters print.
    # Use cpgrep to print 30 characters before and after search patttern.
    if [ $# -eq 2 ] ; then
        # Format was 'cgrep "search string" /path/to/filename'
        grep -o -P ".{0,30}$1.{0,30}" "$2"
    else
        # Format was 'cat /path/to/filename | cgrep "search string"
        grep -o -P ".{0,30}$1.{0,30}"
    fi
} # cgrep()

Inilah yang terlihat seperti beraksi:

$ ll /tmp/rick/scp.Mf7UdS/Mf7UdS.Source

-rw-r--r-- 1 rick rick 25780 Jul  3 19:05 /tmp/rick/scp.Mf7UdS/Mf7UdS.Source

$ cat /tmp/rick/scp.Mf7UdS/Mf7UdS.Source | cgrep "Link to iconic"

1:43:30.3540244000 /mnt/e/bin/Link to iconic S -rwxrwxrwx 777 rick 1000 ri

$ cgrep "Link to iconic" /tmp/rick/scp.Mf7UdS/Mf7UdS.Source

1:43:30.3540244000 /mnt/e/bin/Link to iconic S -rwxrwxrwx 777 rick 1000 ri

File yang dimaksud adalah satu baris 25K terus menerus dan tidak ada harapan untuk menemukan apa yang Anda cari menggunakan reguler grep.

Perhatikan dua cara berbeda untuk memanggil metode cgrepparalel itu grep.

Ada cara yang "lebih baik" untuk membuat fungsi di mana "$ 2" hanya diteruskan saat disetel yang akan menghemat 4 baris kode. Saya tidak memiliki itu berguna. Sesuatu seperti ${parm2} $parm2. Jika saya menemukannya, saya akan merevisi fungsi dan jawaban ini.

WinEunuuchs2Unix
sumber
0

Dengan gawk, Anda dapat menggunakan fungsi pencocokan:

    x="hey there how are you"
    echo "$x" |awk --re-interval '{match($0,/(.{4})how(.{4})/,a);print a[1],a[2]}'
    ere   are

Jika Anda setuju dengan perl, solusi yang lebih fleksibel: Berikut ini akan mencetak tiga karakter sebelum pola diikuti dengan pola sebenarnya dan kemudian 5 karakter setelah pola.

echo hey there how are you |perl -lne 'print "$1$2$3" if /(.{3})(there)(.{5})/'
ey there how

Ini juga dapat diterapkan ke kata, bukan hanya karakter. Mengikuti akan mencetak satu kata sebelum string yang cocok.

echo hey there how are you |perl -lne 'print $1 if /(\w+) there/'
hey

Berikut ini akan mencetak satu kata setelah pola:

echo hey there how are you |perl -lne 'print $2 if /(\w+) there (\w+)/'
how

Mengikuti akan mencetak satu kata sebelum pola, lalu kata sebenarnya dan kemudian satu kata setelah pola:

echo hey there how are you |perl -lne 'print "$1$2$3" if /(\w+)( there )(\w+)/'
hey there how
P ....
sumber
0

Anda dapat menggunakan grep regexp untuk menemukan + grep kedua untuk sorotan

echo "some123_string_and_another" | grep -o -P '.{0,3}string.{0,4}' | grep string

23_string_and

masukkan deskripsi gambar di sini

Andrew Zhilin
sumber