Tampilkan semua file hingga cocok

71

grep --before-context 5 menunjukkan 5 baris sebelum pertandingan.

Saya ingin menunjukkan segalanya sebelum pertandingan.
Melakukan grep --before-context 99999999akan berhasil tetapi tidak terlalu ... profesional.

Bagaimana cara menampilkan semua file hingga sesuai?

Nicolas Raoul
sumber

Jawaban:

95

Sed lebih baik untuk itu.

Kerjakan saja:

sed '/PATTERN/q' FILE

Ini berfungsi seperti ini:

Untuk setiap baris, kami melihat apakah cocok dengan /PATTERN:

  • jika ya, kami cetak dan berhenti
  • jika tidak, kami mencetaknya

Ini adalah solusi paling efisien, karena begitu dilihatnya PATTERN, ia berhenti. Tanpa q, sed akan terus membaca sisa file, dan tidak melakukan apa-apa dengan itu. Untuk file besar itu dapat membuat perbedaan.

Trik ini juga dapat digunakan untuk meniru head:

sed 10q FILE
Mikel
sumber
Baru saja mencoba, itu hanya menampilkan baris pertama file ... meskipun pertandingan ada di baris 38.
Nicolas Raoul
Bekerja dengan baik untuk saya. Bisakah Anda memberikan contoh input dan output aktual? Dan perintah yang Anda jalankan apa adanya.
Mikel
Saya telah mencoba perintah Anda sebelum Anda mengeditnya, itu adalah: sed '/ POLA / p; q' FILE
Nicolas Raoul
7
Apa yang harus saya lakukan, jika saya tidak ingin mencetak garis dengan kecocokan pola?
tommy.carstensen
4
@ tommy.carstensen: sed '/PATTERN/Q' FILEakan melewati garis yang cocok. Qadalah ekstensi GNU, jadi itu tidak akan berfungsi dengan sed.
Alex O
37

sed dapat menggantikan sebagian besar fungsi grep.

sed -n '1,/<pattern>/ p' <file>

Ini berarti mencetak dari baris pertama hingga pola cocok.

Beberapa contoh rentang

sed -n '/<pattern>/,$ p' <file> # from pattern to end of file
sed -n '/<pattern1>/,/<pattern2>/ p' <file> # from pattern1 to pattern2
forcefsck
sumber
3
Perintah ini bagus, tetapi Anda bisa berbuat lebih baik. Dengan cara ini ia membaca seluruh file, tetapi dimungkinkan untuk berhenti segera setelah menemukan kecocokan.
Mikel
3
Apa yang harus saya lakukan, jika saya tidak ingin mencetak garis dengan kecocokan pola?
tommy.carstensen
34

cetak hingga dan termasuk kecocokan:

awk '{print} /pattern/ {exit}' filename
sed '/pattern/q' filename

cetak hingga TAPI TIDAK termasuk pertandingan:

awk '/pattern/ {exit} {print}' filename
sed '/pattern/Q' filename
glenn jackman
sumber
11
QKeren tapi afnu khusus gnu, sed -n '/pattern/!p;//q'akan lebih portabel.
don_crissti
@don_crissti: Anda harus membuatnya menjadi jawaban, saya pikir itu jawaban yang bagus (: Saya sedikit penasaran bagaimana cara kerjanya, saya percaya !membuat pberlaku untuk garis yang tidak cocok pattern, tapi kemudian //qmembingungkan saya ...
jwd
2
@don_crissti: ah, saya mengerti - //berarti "ekspresi reguler sebelumnya" (saya pikir itu berarti "cocok dengan string kosong"). Saya pikir versi yang lebih pendek dari solusi yang sama adalah sed -n '/pattern/q;p:?
jwd
@ jwd - memang, itu lebih pendek. 👍
don_crissti
1

grepMetode GNU murni berikut tidak efisien.

Cari semuanya hingga instance pertama dari string " foo " di bilah file , menggunakan tiga greps:

grep -m 1 -B $(grep -n -m 1 foo bar | grep -o '^[0-9]*') foo bar

Mencocokkan hingga instance terakhir dari " foo ":

grep -oPz "(?s)[^\n]*${s}.*?\n.*?foo.*?\n" bar

Catatan: perincian tentang yang terakhir grepdapat ditemukan di: Regex (grep) untuk pencarian multisaluran .

agc
sumber
Mengapa seseorang ingin menggunakan 7 greps (+ pcre) padahal hanya menjalankan satu sedpermintaan saja: sed 'x;/./G;//!x;/foo/p;//s/.*//;x;d'??
don_crissti
@don_crissti, sedkode Anda sepertinya layak dijawab sendiri, atau dapat ditambahkan ke yang lain. Re 7 greps: Karena tidak ada grepjawaban ... (ditambah, jawabannya membantu menunjukkan mengapa tidak.)
agc
Ini bukan kode saya, klik saja ... Bahkan jika itu kode saya, itu tidak menjawab Q di sini jadi saya tidak akan mempostingnya sebagai jawaban.
don_crissti
1

Menambahkan ke jawaban Mikel di atas ...


Untuk mencetak semua baris hingga, tetapi tidak termasuk , baris pertama yang FILEberisi PATTERN, coba:

  • sed '/.*PATTERN.*/{s///;q;}' FILE

Ini cocok dengan seluruh baris yang berisi pola, menggantikannya dengan baris kosong, lalu berhenti tanpa memproses sisa file.


Nota bene:

Cara termudah / paling jelas yang bisa saya pikirkan untuk mencegah mencetak baris baru tambahan di akhir (tanpa melibatkan alat lain), adalah menjalankan sed lagi dan menghapus baris akhir baru:

sed '/.*PATTERN.*/{s///;q;}' FILE | sed '$d'

... dan karena kita sekarang menghapus garis itu, pekerjaan kita sebelumnya berlebihan dan kita dapat menyederhanakan untuk:

sed '/PATTERN/q' FILE | sed '$d'
Jim Grisham
sumber
Jawaban Glenn - dan komentar saya di sana - menunjukkan bagaimana melakukannya dengan seddoa tunggal .
don_crissti
(Terima kasih untuk itu - saya memang melihat komentar Anda pada jawaban AGC tetapi entah melewatkan yang lain atau hanya membaca skimnya karena otak saya tidak suka double-negatif.) Karena saya menggunakan ini di a tcshdan bashalias, saya perlu memastikan saya memiliki solusi satu-jalur yang relatif ringkas yang berfungsi baik dalam standar dan GNU sed(untuk portabilitas); semua persyaratan yang mungkin telah dipenuhi oleh kontribusi Anda. Sebagai seseorang yang menggunakan sed sangat jarang, kebutuhan saya yang paling penting adalah untuk sesuatu yang saya bisa cepat memahami ketika saya ingin dengan mudah mengedit atau re-tujuan itu tahun dari sekarang.
Jim Grisham
1

Untuk orang yang memilih untuk mengingat hanya alat dasar dalam pekerjaan sehari-hari, dan bersedia menerima solusi yang kurang elegan dan kurang efisien:

head -n $(grep -n pattern filename | cut -d: -f1) filename

Jika perintah ini untuk skrip maka saya akan mencari solusi yang lebih elegan (dan mungkin efisien). Jika ini adalah perintah satu kali atau skrip dibuang maka saya tidak peduli.

lesmana
sumber
1
Ide yang bagus, tetapi tiga perintah ketika seseorang akan melakukannya.
Mikel
1
Mengetahui dasar-dasarnya memang sangat bagus. Mengetahui alat yang tepat untuk pekerjaan itu lebih baik.
soulmerge
Jika perintah ini untuk skrip maka saya akan mencari solusi yang lebih elegan (dan mungkin efisien). Jika ini adalah perintah satu kali (atau skrip dibuang), maka saya tidak peduli.
lesmana
0

Anda juga dapat menggunakan salah satu dari yang berikut ini

tac ./test | grep -B $(cat ./test | wc -l) -m 1 'pattern'|tac 

atau

tac ./test |head -n $(tac ./test | grep -n 'pattern' | cut -d: -f1 | head -n 1)|tac

atau

tac ./test |sed ':a;N;$!ba;s/\n/'"pattern"'/g' | sed 's/'"patternpattern"'/\n/g'|head -n 1|sed 's/'"pattern"'/\n/g'|tac

Opsi pertama sangat mirip dengan apa yang disarankan OP hanya itu memastikan ti menunjukkan cukup baris sebelum konteks dengan menghitung baris dalam file

Opsi kedua mencari nomor baris dari pertandingan pertama (Anda bisa mengubahnya juga dengan mengubah 'kepala' bagian dalam) dan daripada menggunakan kepala di nomor itu

Opsi terakhir menggantikan semua baris baru dengan pertandingan dan daripada mengganti dua pertandingan yang berdekatan dengan baris baru. Output dari ini adalah baris untuk setiap blok teks antara dua kecocokan. Setelah itu menggunakan 'head' untuk memilih baris pertama (mengubah blok teks hingga kecocokan pertama) cocok dan kemudian menerjemahkan ulang setiap kecocokan ke baris baru. opsi ini hanya berfungsi jika file dalam format berikut

pattern
texttexttext
texttexttext texttexttext
texttexttexttexttexttexttexttexttext
pattern
texttexttext
pattern 
texttexttext
texttexttexttexttexttexttexttexttext

Dan seterusnya

pengguna122778
sumber
2
pertimbangkan untuk menjelaskan bagaimana ini bekerja, terutama karena sedperintah yang ada di bagian bawah adalah jenis degil.
strugee
opsi pertama sangat mirip dengan apa yang disarankan OP hanya itu memastikan ti menunjukkan cukup banyak kines sebelum konteks dengan menghitung garis di filr,
user122778