Sepertinya saya menyalahgunakan grep
/ egrep
.
Saya mencoba mencari string dalam beberapa baris dan tidak dapat menemukan kecocokan sementara saya tahu bahwa apa yang saya cari harus cocok. Awalnya saya berpikir bahwa regex saya salah tetapi pada akhirnya saya membaca bahwa alat ini beroperasi per baris (juga regex saya sangat sepele sehingga tidak mungkin menjadi masalah).
Jadi alat mana yang akan digunakan untuk mencari pola di beberapa baris?
grep
. Mereka terkait erat tetapi bukan dups, IMO."grep"
menyarankan kata kerja "to grep", dan jawaban teratas, termasuk diterima, jangan gunakan grep.Jawaban:
Berikut ini
sed
salah satu yang akan memberi Andagrep
perilaku seperti melintasi beberapa baris:Bagaimana itu bekerja
-n
menekan perilaku standar pencetakan setiap baris/foo/{}
menginstruksikannya untuk mencocokkanfoo
dan melakukan apa yang ada di dalam squigglies ke garis yang cocok. Gantifoo
dengan bagian awal dari pola.:start
adalah label percabangan untuk membantu kami tetap terhubung sampai kami menemukan akhir dari regex kami./bar/!{}
akan mengeksekusi apa yang ada di squigglies ke baris yang tidak cocokbar
. Gantibar
dengan bagian akhir dari pola.N
menambahkan baris berikutnya ke buffer aktif (sed
menyebutnya ruang pola)b start
akan bercabang tanpa syarat kestart
label yang kita buat sebelumnya agar tetap menambahkan baris berikutnya selama ruang pola tidak mengandungbar
./your_regex/p
mencetak ruang pola jika cocokyour_regex
. Anda harus menggantiyour_regex
dengan seluruh ekspresi yang ingin Anda cocokkan di beberapa baris.sumber
sed: 1: "/foo/{:start /bar/!{N;b ...": unexpected EOF (pending }'s)
sed: unterminated {
kesalahansed
implementasi. Saya mencoba mengikuti rekomendasi dalam jawaban itu untuk membuat skrip di atas memenuhi standar tetapi mengatakan kepada saya bahwa "mulai" adalah label yang tidak ditentukan. Jadi saya tidak yakin apakah ini dapat dilakukan dengan cara yang sesuai standar. Jika Anda mengelolanya, silakan edit jawaban saya.Saya biasanya menggunakan alat yang disebut
pcregrep
yang dapat diinstal di sebagian besar rasa linux menggunakanyum
atauapt
.Untuk misalnya.
Misalkan jika Anda memiliki file yang dinamai
testfile
dengan kontenAnda dapat menjalankan perintah berikut:
untuk melakukan pencocokan pola di beberapa baris.
Selain itu, Anda dapat melakukan hal yang sama dengannya
sed
.sumber
Berikut ini pendekatan yang lebih sederhana menggunakan Perl:
atau (karena JosephR mengambil
sed
rute , saya akan tanpa malu mencuri sarannya )Penjelasan
$f=join("",<>);
: ini membaca seluruh file dan menyimpan kontennya (baris baru dan semua) ke dalam variabel$f
. Kami kemudian mencoba untuk mencocokkanfoo\nbar.*\n
, dan mencetaknya jika cocok (variabel khusus$&
memegang kecocokan terakhir yang ditemukan). The///m
diperlukan untuk membuat ekspresi pertandingan reguler di seluruh baris.The
-0
menetapkan pemisah record masukan. Mengatur ini untuk00
mengaktifkan 'mode paragraf' di mana Perl akan menggunakan baris baru berurutan (\n\n
) sebagai pemisah rekaman. Dalam kasus di mana tidak ada baris baru berturut-turut, seluruh file dibaca (disedot) sekaligus.Peringatan:
Jangan tidak melakukan ini untuk file besar, itu akan memuat seluruh file ke dalam memori dan yang mungkin menjadi masalah.
sumber
Salah satu cara untuk melakukan ini adalah dengan Perl. misal inilah isi file bernama
foo
:Sekarang, inilah beberapa Perl yang akan cocok dengan setiap baris yang dimulai dengan foo diikuti oleh baris yang dimulai dengan bar:
Perl, rusak:
while(<>){$all .= $_}
Ini memuat seluruh input standar ke variabel$all
while($all =~
Sementara variabelall
memiliki ekspresi reguler .../^(foo[^\n]*\nbar[^\n]*\n)/m
Regex: foo di awal baris, diikuti oleh sejumlah karakter non-baris baru, diikuti oleh baris baru, segera diikuti oleh "bar", dan sisa baris dengan bar di dalamnya./m
pada akhir regex berarti "cocok dengan banyak garis"print $1
Cetak bagian dari regex yang ada dalam tanda kurung (dalam hal ini, seluruh ekspresi reguler)s/^(foo[^\n]*\nbar[^\n]*\n)//m
Hapus kecocokan pertama untuk regex, sehingga kami dapat mencocokkan beberapa kasus regex dalam file yang dimaksudDan hasilnya:
sumber
perl -n0777E 'say $& while /^foo.*\nbar.*\n/mg' foo
Alternatif grep sift mendukung pencocokan multiline (disclaimer: Saya penulis).
Misalkan
testfile
mengandung:sift -m '<description>.*?</description>'
(tampilkan garis yang berisi deskripsi)Hasil:
sift -m '<description>(.*?)</description>' --replace 'description="$1"' --no-filename
(ekstrak dan format ulang deskripsi)Hasil:
sumber
Cukup grep normal yang mendukung
Perl-regexp
parameterP
akan melakukan pekerjaan ini.(?s)
disebut pengubah DOTALL yang membuat titik di regex Anda agar tidak hanya cocok dengan karakter tetapi juga garis terputus.sumber
-P
opsiSaya memecahkan ini untuk saya menggunakan opsi grep dan -A dengan grep lain.
Opsi -A 1 mencetak 1 baris setelah baris yang ditemukan. Tentu saja itu tergantung pada kombinasi file dan kata Anda. Tetapi bagi saya itu adalah solusi tercepat dan dapat diandalkan.
sumber
Misalkan kita memiliki file test.txt yang berisi:
Kode berikut dapat digunakan:
Untuk output berikut:
sumber
Jika kita ingin mendapatkan teks di antara 2 pola tidak termasuk diri mereka sendiri.
Misalkan kita memiliki file test.txt yang berisi:
Kode berikut dapat digunakan:
Untuk output berikut:
Bagaimana cara kerjanya, mari kita buat langkah demi langkah
/foo/{
dipicu ketika baris berisi "foo"n
ganti spasi pola dengan baris berikutnya, yaitu kata "di sini"b gotoloop
cabang ke label "gotoloop":gotoloop
mendefinisikan label "gotoloop"/bar/!{
jika polanya tidak mengandung "bar"h
ganti ruang tunggu dengan pola, jadi "di sini" disimpan di ruang penyimpananb loop
cabang ke label "loop":loop
mendefinisikan label "loop"N
menambahkan pola ke ruang palka.Sekarang tahan ruang berisi:
"di sini"
"adalah"
:gotoloop
Kita sekarang pada langkah 4, dan loop sampai satu baris berisi "bar"/bar/
loop selesai, "bar" telah ditemukan, itu adalah ruang polag
ruang pola diganti dengan ruang pegang yang berisi semua garis antara "foo" dan "bar" yang telah disimpan selama loop utamap
salin ruang pola ke output standarSelesai!
dan multiline loop
sumber