Mengapa 'grep -q' mengkonsumsi seluruh file input?


23

Pertimbangkan file input berikut:

1
2
3
4

Lari

{ grep -q 2; cat; } < infile

tidak mencetak apa pun. Saya berharap untuk mencetak

3
4

Saya bisa mendapatkan hasil yang diharapkan jika saya mengubahnya

{ sed -n 2q; cat; } < infile

Mengapa perintah pertama tidak mencetak output yang diharapkan?
Ini adalah file input yang dapat dicari dan sesuai standar dalam OPSI :

-q
      Quiet. Nothing shall be written to the standard output, regardless of 
      matching lines. Exit with zero status if an input line is selected.

dan lebih jauh ke bawah, di bawah APLIKASI PENGGUNAAN (menekankan tambang):

The -qpilihan menyediakan sarana mudah menentukan apakah atau tidak pola (atau string) ada di kelompok file. Saat mencari beberapa file, ini memberikan peningkatan kinerja ( karena dapat berhenti segera setelah menemukan kecocokan pertama ) [...]

Sekarang, sesuai standar yang sama (dalam Pendahuluan , di bawah INPUT FILES )

Ketika sebuah utilitas standar membaca file input yang dicari dan berakhir tanpa kesalahan sebelum mencapai akhir file, utilitas harus memastikan bahwa offset file dalam deskripsi file terbuka diposisikan dengan baik hanya melewati byte terakhir yang diproses oleh utilitas [. ..]

tail -n +2 file
(sed -n 1q; cat) < file
...

Perintah kedua setara dengan yang pertama hanya ketika file dicari.


Mengapa grep -qmengkonsumsi seluruh file?


Ini gnu grepjika itu penting (meskipun Kusalananda baru saja mengkonfirmasi hal yang sama terjadi pada OpenBSD)


OpenBSD grepadalah fork dari sesuatu yang disebut FreeGrep , jika ada yang bertanya-tanya.
Kusalananda

Jawaban:


37

grep memang berhenti lebih awal, tetapi buffer inputnya sehingga tes Anda terlalu pendek (dan ya, saya menyadari tes saya tidak sempurna karena tidak dapat dicari):

seq 1 10000 | (grep -q 2; cat)

dimulai pada 6776 di sistem saya. Yang cocok dengan buffer 32KiB yang digunakan secara default di GNU grep:

seq 1 6775 | wc

output

   6775    6775   32768

Perhatikan bahwa POSIX hanya menyebutkan peningkatan kinerja

Saat mencari beberapa file

Itu tidak menetapkan harapan untuk peningkatan kinerja karena sebagian membaca satu file.


2

Ini jelas karena buffering yang grepmempercepat hal. Ada alat yang secara khusus dirancang untuk membaca karakter sebanyak yang diminta dan tidak lebih. Salah satunya adalah expect:

{ expect -c "log_user 0; expect 2"; cat; } < infile

Saya tidak memiliki sistem untuk mencoba ini, tetapi saya percaya expectakan memakan segalanya sampai bertemu dengan string yang diharapkan ( 2), dan kemudian berakhir, meninggalkan sisa input untuk cat.


1

Anda membingungkan sed dan grep.

Untuk perintah sed, -2qmengatakan untuk keluar dari iterasi saat ini jika pada baris kedua, -nopsi mengatakan untuk berfungsi dengan tenang, sehingga Anda akan mendapatkan semua baris setelah baris ke-2.

Perintah grep berjalan secara default untuk menampilkan semua baris yang cocok - tetapi -qopsi mengatakan untuk tidak menampilkan apa pun ke stdout. jadi, jika input berisi "2" itu akan memiliki nilai keluar SUKSES, jika tidak KEGAGALAN. Apa itu tergantung pada sistem operasi dan shell Anda. Jadi, biasanya Anda akan mengetahui apakah garis cocok dengan memeriksa nilai keluar dari proses grep. Ini berguna dalam saluran pipa di mana Anda ingin tahu apakah input Anda mengandung beberapa nilai sebagai ujian. Misalnya

if grep -q 'crash' <somelog.log ; then report_crash_via_email ; fi

Dalam hal ini kami benar-benar tidak peduli untuk melihat semua garis yang cocok, kami hanya peduli jika setidaknya ada satu. The report_crash_via_emailproses / fungsi kemudian dapat pergi dan kembali membuka file, atau tidak.

Jika Anda ingin proses grep Anda BERHENTI setelah menemukan karakter "2" - itu tidak akan secara default, itu akan memeriksa setiap baris yang mencari untuk melihat apakah itu cocok - Anda perlu mengatakannya untuk melakukan itu. Saklar baris perintah untuk itu adalah -m <value>. Jadi untuk kasus Anda grep -q -m1 2,.


6
Jawaban Anda adalah informasi yang berguna untuk penggunaan umum greptetapi pertanyaan ini menanyakan tentang sesuatu yang lebih halus dan esoteris. Sepertinya Anda terlalu cepat membaca pertanyaan untuk memahami perilaku aktual yang ditanyakan. Selain itu, GNU grep tidak berhenti mencari ketika digunakan dengan -q(sebagaimana diizinkan dalam kutipan dari spesifikasi POSIX): Halaman manual untuk GNU grep menyatakan bahwa ia "Segera keluar dengan status nol jika ada kecocokan yang ditemukan" . FWIW, saya telah mengedit pertanyaan Anda untuk menunjukkan bagaimana Anda dapat memformat posting selanjutnya. Welcom ke Stack Exchange .
Anthony G - keadilan untuk Monica

Yang mengatakan, jawaban @ user212377 benar: dalam hal grepini ditanya apakah '2' ada dalam file, tidak lebih dan tidak kurang. Itu tidak berperilaku seperti seddan mengkonsumsi catatan hingga saat itu dan meninggalkan sisanya untuk diproses lebih lanjut. Bunyinya sampai ia tahu ada '2' atau tidak ada, menutup file, dan mengembalikan hasilnya.
Keith Davies

grepsebenarnya hanya 'menghabiskan seluruh file' (mengabaikan pertimbangan buffering) jika string pencarian tidak ada dalam file (yang dapat dibuktikan hanya dengan memeriksa seluruh file). Kurang dari itu, pembacaan file berhenti , file ditutup, dan SUKSES dikembalikan.
Keith Davies
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.