Diberikan contoh minimal ini
( echo "LINE 1" ; sleep 1 ; echo "LINE 2" ; )
itu menghasilkan LINE 1
dan kemudian, setelah satu detik, menghasilkan LINE 2
, seperti yang diharapkan .
Jika kita menyalurkan ini ke grep LINE
( echo "LINE 1" ; sleep 1 ; echo "LINE 2" ; ) | grep LINE
perilakunya sama seperti dalam kasus sebelumnya, seperti yang diharapkan .
Jika, sebagai alternatif, kami pipa ini ke cat
( echo "LINE 1" ; sleep 1 ; echo "LINE 2" ; ) | cat
sekali lagi tingkah lakunya sama, seperti yang diharapkan .
Namun , jika kita menyalurkan ke grep LINE
, dan kemudian ke cat
,
( echo "LINE 1" ; sleep 1 ; echo "LINE 2" ; ) | grep LINE | cat
tidak ada output sampai satu detik berlalu, dan kedua garis segera muncul pada output, yang tidak saya harapkan .
Mengapa ini terjadi dan bagaimana saya bisa membuat versi terakhir untuk berperilaku dengan cara yang sama seperti tiga perintah pertama?
cat
menggabungkan file. Apa yang ingin Anda lakukan dengan menyalurkancat
?cat
cukup membacastdin
dan menghasilkanstdout
. Tentu saja, saya datang dengan pertanyaan ini dengan banyak hal rumit di tempatecho
dancat
, tetapi ini ternyata tidak relevan, karena masalah muncul dengan contoh yang jauh lebih sederhana.Jawaban:
Ketika (setidaknya GNU)
grep
output bukan terminal, itu output buffer, yang menyebabkan perilaku yang Anda lihat. Anda dapat menonaktifkan ini baik menggunakan GNUgrep
's--line-buffered
pilihan:atau
stdbuf
utilitas:Matikan buffering in pipe memiliki lebih banyak tentang topik ini.
sumber
Penjelasan yang disederhanakan
Seperti banyak utilitas, ini bukan sesuatu yang khas untuk satu program,
grep
bervariasi keluaran standar antara menjadi buffer garis dan buffer penuh . Dalam kasus sebelumnya, pustaka C buffer menghasilkan data dalam memori sampai buffer yang menahan data tersebut diisi atau karakter linefeed ditambahkan ke dalamnya (atau program berakhir dengan bersih), di mana ia dipanggilwrite()
untuk benar-benar menulis konten buffer. Dalam kasus terakhir, hanya buffer dalam memori yang penuh (atau program berakhir dengan bersih) yang memicuwrite()
.Penjelasan lebih rinci
Ini adalah penjelasan yang terkenal, tapi sedikit salah. Bahkan, output standar tidak buffered garis tetapi buffered pintar di perpustakaan GNU C dan perpustakaan BSD C. Output standar adalah juga memerah ketika membaca standar masukan kehabisan nya penyangga di memori (input pre-read) dan C perpustakaan harus memanggil
read()
untuk mengambil beberapa masukan lebih dan itu adalah membaca awal baris baru. (Salah satu alasan untuk ini adalah untuk mencegah kebuntuan ketika program lain menghubungkan dirinya sendiri ke kedua ujung filter dan berharap untuk dapat mengoperasikan baris-demi-baris, bergantian antara menulis ke filter dan membaca dari itu, seperti "proses-proses" di GNUawk
sebagai contoh.)Pengaruh perpustakaan C
grep
dan utilitas lain melakukan ini - atau, lebih tepatnya, pustaka C yang mereka gunakan melakukan ini, karena ini adalah fitur pemrograman yang didefinisikan dalam bahasa C - berdasarkan pada apa yang mereka deteksi sebagai keluaran standar. Jika (dan hanya jika) itu bukan perangkat interaktif, mereka memilih buffering penuh, atau mereka memilih buffering pintar. Sebuah pipa dianggap bukan perangkat interaktif, karena definisi menjadi perangkat interaktif, setidaknya di dunia Unix dan Linux, pada dasarnya adalahisatty()
panggilan yang mengembalikan true untuk deskriptor file yang relevan.Penanganan untuk menonaktifkan buffering penuh
Beberapa utilitas seperti
grep
memiliki opsi istimewa seperti--line-buffered
itu mengubah keputusan ini, yang seperti yang Anda lihat salah nama. Tetapi sebagian kecil dari program filter yang dapat digunakan sebenarnya memiliki opsi seperti itu.Lebih umum, seseorang dapat menggunakan alat yang menggali internal tertentu dari perpustakaan C dan mengubah pengambilan keputusannya (yang memiliki masalah keamanan jika program yang akan diubah diatur-UID, dan juga khusus untuk perpustakaan C tertentu, dan memang khusus untuk program yang ditulis dalam atau berlapis di atas bahasa C), atau alat seperti
ptybandage
itu tidak mengubah internal program tetapi hanya menempatkan terminal pseudo sebagai output standar sehingga keputusan keluar sebagai "interaktif", untuk mempengaruhi ini.Bacaan lebih lanjut
sumber
grep
, tetapi dari panggilan pustaka yang mendasarinya,setbuf
/setvbuf
. Saya tidak tahu tentang referensi online yang dapat diandalkan untuk standar C, tetapi misalnya halaman manual Linux dan FreeBSD bersama dengan deskripsi POSIXsetvbuf
menyebutnya "line buffered". Bahkan konstanta simbolis untuk itu adalah_IOLBF
.Menggunakan
untuk membuat grep tidak buffer lebih dari satu baris sekaligus.
sumber