Saya tidak mengerti bagaimana data mengalir dalam pipa dan berharap seseorang dapat mengklarifikasi apa yang sedang terjadi di sana.
Saya pikir pipa perintah memproses file (teks, array string) sejalan dengan cara baris. (Jika setiap perintah itu sendiri bekerja baris demi baris.) Setiap baris teks melewati pipeline, perintah jangan menunggu sebelumnya untuk menyelesaikan pemrosesan seluruh input.
Tapi sepertinya tidak demikian.
Ini adalah contoh uji. Ada beberapa baris teks. Saya huruf besar dan ulangi setiap baris dua kali. Saya melakukannya dengan cat text | tr '[:lower:]' '[:upper:]' | sed 'p'
.
Untuk mengikuti proses ini, kita dapat menjalankannya "secara interaktif" - lewati nama file input cat
. Setiap bagian dari pipa berjalan baris demi baris:
$ cat | tr '[:lower:]' '[:upper:]'
alkjsd
ALKJSD
sdkj
SDKJ
$ cat | sed 'p'
line1
line1
line1
line 2
line 2
line 2
Tetapi pipeline lengkap menunggu saya untuk menyelesaikan input dengan EOF
dan hanya kemudian mencetak hasilnya:
$ cat | tr '[:lower:]' '[:upper:]' | sed 'p'
I am writing...
keep writing...
now ctrl-D
I AM WRITING...
I AM WRITING...
KEEP WRITING...
KEEP WRITING...
NOW CTRL-D
NOW CTRL-D
Apakah seharusnya begitu? Mengapa tidak baris demi baris?
cat
buffering sampai stdin ditutup.tr
dansed
lakukan garis proses daricat
sebelum stdin ditutupJawaban:
Ada aturan buffering umum yang diikuti oleh pustaka I / O standar C (
stdio
) yang digunakan sebagian besar program unix. Jika output pergi ke terminal, itu memerah pada akhir setiap baris; jika tidak maka akan memerah hanya ketika buffer (8K pada sistem Linux / amd64 saya; bisa berbeda pada Anda) penuh.Jika semua utilitas Anda mengikuti aturan umum, Anda akan melihat output tertunda dalam semua contoh Anda (
cat|sed
,cat|tr
, dancat|tr|sed
). Tapi ada pengecualian: GNUcat
tidak pernah mendukung outputnya. Entah itu tidak menggunakanstdio
atau mengubahstdio
kebijakan buffering default .Saya bisa yakin Anda menggunakan GNU
cat
dan bukan unix laincat
karena yang lain tidak akan berperilaku seperti ini. Unix tradisionalcat
memiliki-u
opsi untuk meminta keluaran tanpa buffer. GNUcat
mengabaikan-u
opsi karena outputnya selalu tidak dibuat-buat.Jadi, setiap kali Anda memiliki pipa dengan
cat
di sebelah kiri, dalam sistem GNU, bagian data melalui pipa tidak akan tertunda. Thecat
bahkan tidak akan baris demi baris - terminal Anda melakukan hal itu. Saat Anda mengetikkan input untuk cat, terminal Anda berada dalam mode "kanonik" - berbasis garis, dengan tombol pengeditan seperti backspace dan ctrl-U menawarkan Anda kesempatan untuk mengedit baris yang telah Anda ketikkan sebelum mengirimkannya Enter.Dalam
cat|tr|sed
contoh,tr
masih menerima data daricat
segera setelah Anda menekan Enter, tetapitr
mengikutistdio
kebijakan default: outputnya adalah pipa, sehingga tidak memerah setelah setiap baris. Itu menulis ke pipa kedua ketika buffer penuh, atau ketika EOF diterima, mana yang lebih dulu.sed
juga mengikutistdio
kebijakan default, tetapi outputnya pergi ke terminal sehingga akan menulis setiap baris segera setelah selesai dengannya. Ini memiliki efek pada berapa banyak Anda harus mengetik sebelum sesuatu muncul di ujung pipa - jikased
sedang memblokir-buffer outputnya, Anda harus mengetik dua kali lebih banyak (untuk mengisitr
buffer output dansed
output penyangga).GNU
sed
memiliki-u
opsi jadi jika Anda membalik urutan dan menggunakancat|sed -u|tr
Anda akan melihat output muncul kembali secara instan. (sed -u
Pilihannya mungkin tersedia di tempat lain tetapi saya tidak berpikir itu tradisi unix kuno seperticat -u
) Sejauh yang saya tahu tidak ada opsi yang setara untuk itutr
.Ada utilitas yang disebut
stdbuf
yang memungkinkan Anda mengubah mode buffering dari setiap perintah yang menggunakanstdio
default. Agak rapuh karena digunakanLD_PRELOAD
untuk mencapai sesuatu yang tidak didukung oleh pustaka C, tetapi dalam kasus ini tampaknya berfungsi:sumber
tee
dandd
juga biasanya bermain dengan aturannya sendiri. Ketika dikombinasikan secara imajinatif, ketiga alat ini dapat dengan mudah meniadakan kebutuhan apa punstdbuf
dalam pipa latar belakang.Ini benar-benar membuat saya berpikir untuk mengerti dan bahkan lebih untuk menjawab. Pertanyaan bagus (saya akan menjawabnya selanjutnya).
Anda lalai untuk mencoba
tr | sed
item debug Anda di atas:Jadi ternyata
tr
penyangga. Pelajari sesuatu yang baru setiap hari!EDIT :
Saat saya memikirkan hal ini, kami telah mengisolasi penyebabnya, tetapi tidak memberikan penjelasan. Jika Anda
cat | tr
, itu menulis segera, jika Andacat | sed
, itu menulis segera, tetapi jika Andatr | sed
, itu menunggu untukEOF
. Saya akan menyarankan jawabannya mungkin dimakamkantr
ataused
kode sumber, dan bukan masalah pipa.EDIT :
Saya melihat Wumpus memberikan penjelasan saat saya mengetik edit terakhir. Terima kasih!
sumber
stdbuf
yang mungkin juga bermanfaat. unix.stackexchange.com/questions/182537/...