Bagaimana cara mencari teks dalam file yang mengabaikan baris baru?

11

Saya ingin mencari teks yang dapat dibagi beberapa baris dalam file. Grep yang akan mengabaikan jeda baris dan mengembalikan rentang garis yang cocok.

misalnya saya akan mencari is an example file, dan berharap itu dapat ditemukan di file berikut:

Ini adalah
sebuah
contoh file.

Tidak bergantung pada ruang depan atau belakang, sepenuhnya mengabaikan semua bentuk ruang putih mungkin yang terbaik (idealnya, memperlakukan urutan ruang putih sebagai ruang tunggal).


Salah satu solusi yang tidak ideal adalah tr '\n' ' ' | grep, yang membedakan antara pertandingan dan non-pertandingan, tetapi tidak menunjukkan pertandingan, juga tidak menangani file besar dengan baik.

Nikana Reklawyks
sumber
pada SO (tidak ada jawaban pasti): stackoverflow.com/q/1858312/1449460
Nikana Reklawyks
Sebagai catatan tambahan, pencarian emacs tampaknya melakukan pekerjaan ( isearch-forward)
Nikana Reklawyks
Begitu juga Vim ini: /This\_sis. Untuk lebih jelasnya: :help \_s.
lcd047
Tambahkan baris ini di akhir baris pencarian Anda: tr -n "\ n" Ini akan menghapus semua baris baru. Semoga bantuan ini!
Dan Howel

Jawaban:

12

GNU grepdapat melakukannya

grep -z 'is\san\sexample\sfile.' file

Untuk memenuhi beberapa poin yang muncul dalam komentar ada beberapa modifikasi pada skrip:

 grep -oz '^[^\n]*\bis\s*an\s*example\s*file\.[^\n]*' file

Mengenai file besar saya tidak memiliki imajinasi keterbatasan memori tetapi dalam kasus masalah Anda bebas untuk menggunakan sed

sed '/\bis\b/{
          :1
          N
          /file\.\|\(\n.*\)\{3\}/!b1
         }
     /\<is\s*an\s*example\s*file\./p
     D' file

yang menyimpan tidak lebih dari 4-baris (karena 4 kata dalam pola) dalam memori ( \(\n.*\)\{3\}).

Costas
sumber
5
Seperti yang saya yakin Anda tahu, -zopsi memberitahu grepuntuk memperlakukan baris baru sebagai karakter teks biasa, dan mencari byte byte untuk memisahkan catatan. Dalam file teks tanpa byte byte (yaitu, kasus khas), grep -zakan memperlakukan seluruh file sebagai satu baris. Jadi (1) ini menimbulkan pertanyaan tentang seberapa baik ia dapat menangani file besar, dan (2) jika menemukan kecocokan, itu akan menulis seluruh file, tidak memberikan petunjuk tentang lokasi pertandingan. (3) OP mengatakan, "idealnya, memperlakukan urutan ruang putih sebagai ruang tunggal," jadi Anda harus menggunakan \s+dan menambahkan -E.
G-Man Mengatakan 'Reinstate Monica'
1
@ G-Man Terima kasih atas komentarnya. Silakan lihat jawaban yang diedit.
Costas
1
(0) Ah, -o; Saya terus lupa tentang itu. Cara cerdas untuk menggunakannya. (1) grepJawaban baru Anda dimulai ^[\n]*; itu salah ketik untuk [^\n]*. (2) kataku dengan \s+sengaja.  be\s*littleakan cocok belittle, dan care\s*lessakan cocok careless. Tapi saya kira itu masalah kecil. Dan, jika Anda tidak ingin menggunakan -E, Anda dapat menggunakan "versi orang miskin" \s+, yaitu \s\s*,. (3) sedPerintah yang bagus . Ini bisa gagal jika ada baris kosong (sehingga frasa empat kata dapat tersebar di lebih dari empat baris); Saya dapat memperbaikinya dengan menambahkan s/\n\s*\n/\n/.
G-Man Mengatakan 'Reinstate Monica'
@ G-Man Terima kasih againg. Komentar Anda sangat berguna. Saya telah mencoba untuk memposting kode portabel lebih atau kurang karena anggota terkenal setiap kali mendorong saya untuk melakukannya. Pokoknya bahkan tanpa -EAnda baja dapat digunakan +dalam \s\+bentuk. Garis-garis kosong di dalam pola tampaknya dibuat-buat.
Costas
Saya sedang memikirkan dokumen teks paginasi, seperti RFCs - ISTR yang halaman manual terlihat seperti itu pada beberapa sistem (atau memang ) - tetapi, pada pemikiran lebih lanjut, terpikir oleh saya bahwa sebagian besar dokumen tersebut memiliki header halaman dan / atau footer. (s) yang perlu dihapus sebelum Anda bisa berharap kepada grepmereka untuk frasa.
G-Man Mengatakan 'Reinstate Monica'
7

Coba ini:

pcregrep -M '\bThis\s+is\b' <<EOT
This
is
an example
file.
EOT
lcd047
sumber
Apakah saya harus mengetik \s5 kali jika mencari "ini pola yang sangat panjang"?
Nikana Reklawyks
1
Ya: intinya \scocok dengan spasi, dan baris baru adalah "spasi".
lcd047
Maksud saya, bagaimana jika file tersebut This\nis a very\nlong pattern, dan saya tidak tahu di mana garis putus mungkin terjadi. Saya harus mencari This\sis\sa\svery\slong\spattern, kan? (yang menjadi membosankan karena panjang pola meningkat atau disisipkan dari tempat lain)
Nikana Reklawyks
2
Kemudian Anda melakukannya seperti ini: pcregrep -M "$( echo 'This is a very long pattern' | sed 's/ /\\s+/g' )" file.
lcd047