Bisakah saya menonaktifkan buffering untuk tr

10

trtampaknya buffer inputnya sehingga perintah LongRunningCommand|tr \\n ,ini hanya akan mulai menghasilkan output setelah beberapa kilobytes input dari LongRunningCommand telah terakumulasi.

Apakah ada cara untuk memaksa trmenghentikan buffering ini atau perintah lain yang dapat mengganti baris baru dengan karakter lain tanpa buffering?


PS Saya sudah mencoba dua saran pertama dari Matikan buffering di pipa tanpa hasil.

ndemou
sumber
1
apakah Anda berlaku stdbufuntuk LongRunningCommand atau tr, atau keduanya, berbeda?
meuh
Untuk keduanya seperti ini:stdbuf -o0 fping -aAq -r2 -g 10.30.0.1 10.30.0.255 2>/dev/null | stdbuf -i0 tr \\n ,
ndemou
fping -qmengatakan "Jangan tampilkan hasil per-probe, tetapi hanya ringkasan akhir", jadi mungkin hanya satu penulisan panjang di akhir?
meuh
Tidak ada perintah fping bekerja dengan baik dengan sendirinya. Terima kasih banyak atas sarannya
ndemou
2
Saya pikir masalah buffering sebenarnya dalam output dari tr. Coba|stdbuf -i0 -o0 tr ...
meuh

Jawaban:

12

Perintah biasanya tidak buffer input mereka. Mereka akan melakukan read()untuk potongan besar, tetapi ketika membaca dari sebuah pipa, jika tidak ada banyak byte dalam pipa, read()pemanggilan sistem akan kembali dengan sebanyak karakter yang ada dan aplikasi umumnya akan bekerja dengan itu jika dapat .

Pengecualian penting untuk hal itu adalah mawkyang akan terus kembali read()sampai buffer input penuh.

Aplikasi melakukan buffer output mereka (stdout). Perilaku yang biasa adalah bahwa jika output pergi ke tty, maka buffering akan menjadi garis-bijaksana (yaitu, itu tidak akan mulai menulis ke stdout sampai memiliki baris penuh ke output, atau blok-penuh untuk sangat garis panjang), sedangkan untuk setiap jenis file lainnya, buffering adalah dengan blok (yaitu, ia tidak akan mulai menulis sampai memiliki satu blok penuh untuk ditulis (sekitar 4KiB / 8KiB ... tergantung pada perangkat lunak dan sistemnya) )).

Jadi dalam kasus Anda LongRunningCommandkemungkinan buffer outputnya dengan blok (karena outputnya adalah pipa dan bukan tty), dan trkemungkinan buffer outputnya dengan garis karena outputnya mungkin terminal.

Tapi, karena Anda menghapus setiap karakter baris baru dari outputnya, itu tidak akan pernah menampilkan baris, jadi buffering akan dengan blok.

Jadi di sini Anda ingin menonaktifkan buffering untuk keduanya LongRunningCommanddan tr. Pada sistem GNU atau FreeBSD:

stdbuf -o0 LongRunningCommand | stdbuf -o0 tr '\n' ,

Perhatikan bahwa jika Anda ingin bergabung dengan garis dengan koma, pendekatan yang lebih baik adalah menggunakan paste -sd , -. Dengan begitu output akan diakhiri oleh karakter baris baru (Anda mungkin masih perlu menonaktifkan buffering).

Stéphane Chazelas
sumber
@ mikeserv. Ya, dan yang menggunakan buffering stdio dan tidak memanggil setvbuf / setbuffer ... dengan sendirinya dan bukan shell builtin. Tetapi umumnya pada sistem GNU dan FreeBSD, semua persyaratan tersebut terpenuhi.
Stéphane Chazelas
oh Saya hanya belajar sendiri beberapa hari yang lalu ketika saya kecewa bahwa saya tidak dapat mempengaruhi stream i / o untuk kompilasi statis saya sed. maaf jika itu mengganggu - tetapi saya tidak menyadari itu adalah pengetahuan umum. saya kira itu menggunakan LD_PRELOAD.
mikeserv
Terima kasih atas penjelasan menyeluruh tentang apa yang terjadi Stéphane. Sangat dihargai
ndemou
5

Untuk mengganti baris baru dengan ",", Anda dapat menjalankan

awk '{ printf "%s,", $0 }'

GNU awk ( gawk) dan Solaris nawkakan berjalan dengan line buffering pada stdin dan tidak ada buffering stdout ketika output menuju terminal. Jika awk Anda mawk, yang terjadi pada Ubuntu, Anda dapat memberikannya -W interactiveopsi untuk mendapatkan perilaku buffering yang sama.

Tandai Plotnick
sumber