Perlu penjelasan dari pengguna yang kuat untuk perilaku yang tidak terduga seperti itu:
ps -eF | { head -n 1;grep worker; }
UID PID PPID C SZ RSS PSR STIME TTY TIME CMD
root 441 2 0 0 0 2 paź15 ? 00:00:00 [kworker/2:1H]
semuanya terlihat ok
ls -la / | { head -n 1;grep sbin; }
hanya menampilkan keluaran dari head
... Saya memikirkan stdout 2>&1
dan tidak bekerja bagi saya itu aneh, ada penjelasan atau menyarankan cara menanganinya?
head
dangrep
melakukan apa-apa di sana.Jawaban:
Saya melakukan investigasi menggunakan
strace
dan tampaknya karena cara program di sisi kiri pipa itu menulis ke terminal. Ketikals
perintah dieksekusi itu menulis semua data dalam satuwrite()
. Ini menyebabkanhead
mengkonsumsi semua stdin.Di sisi lain
ps
menulis data dalam kumpulan, jadi hanya yang pertamawrite()
dikonsumsi olehhead
, dan kemudian ada. Nanti panggilan kewrite()
akan pergi ke proses yang baru melahirkangrep
.Ini berarti bahwa itu tidak akan berfungsi jika proses yang Anda coba
grep
untuk tidak terjadi di yang pertamawrite()
, karenagrep
tidak bisa melihat semua data (itu melihat bahkan kurang dari sekedar data minus baris pertama).Berikut adalah contoh mencoba untuk mencoba pid 1 di sistem saya:
ps -eF
Contoh Anda hanya berfungsi secara kebetulan.sumber
write()
panggilan. Jikahead
lambat untuk melakukanread()
panggilan itu (sehingga penyangga pipa memiliki semua data di dalamnya), itu akan menunjukkan perilaku yang sama di keduals
danps
.Ini disebabkan oleh buffering di glibc. Dalam kasus
ls
output dalam satu buffer internal dan dengan demikian diteruskan hanya kehead
. Untukps -eF
, output lebih besar dan begituhead
selesai, berikut inigrep
mendapatkan bagian yang tersisa dari (tetapi tidak keseluruhan) dari outputps
.Anda dapat membuangnya dengan membatalkan penyangga pipa - misalnya dengan
sed -u
(Saya tidak yakin itu bukan ekstensi GNU):sumber
Apa yang terjadi adalah yang
head -n 1
membaca lebih dari 1 baris. Untuk throughput yang optimal, head membaca potongan byte, sehingga mungkin membaca 1024 byte sekaligus, dan kemudian mencari melalui byte tersebut untuk jeda baris pertama. Karena pemutusan garis mungkin terjadi di tengah-tengah 1024 byte itu, sisa data akan hilang. Itu tidak bisa dimasukkan kembali ke pipa. Jadi proses selanjutnya yang dijalankan hanya mendapatkan byte 1025 dan terus.Perintah pertama Anda berhasil untuk berhasil karena
kworker
prosesnya adalah setelah potongan pertama yanghead
berbunyi.Agar ini berfungsi,
head
harus membaca 1 karakter sekaligus. Tapi ini sangat lambat, jadi tidak.Satu-satunya cara untuk melakukan sesuatu seperti ini secara efisien adalah dengan memiliki satu proses melakukan "kepala" dan "grep".
Berikut adalah 2 cara untuk melakukan ini:
atau
Ada banyak lagi ...
sumber
Jika Anda hanya menginginkan satu atau dua baris pertama, jenis trik berikut ini berfungsi dan menghindari masalah buffering yang disebabkan oleh penggunaan dua perintah berbeda untuk membaca aliran keluaran:
Ini
read
built-in ke shell dan tidak mengkonsumsi seluruh buffer input hanya untuk output satu baris, jadi menggunakanread
semua sisa output untuk perintah berikut.Jika Anda ingin menonjolkan masalah buffering yang ditunjukkan oleh contoh Anda yang menggunakan dua perintah berbeda, tambahkan a
sleep
untuk menghilangkan masalah waktu dan izinkan perintah di sebelah kiri untuk menghasilkan semua outputnya sebelum perintah di sebelah kanan mencoba membaca salah satu Itu:Sekarang, kedua contoh di atas gagal dengan cara yang sama -
head
membaca seluruh buffer dari output hanya untuk menghasilkan satu baris, dan buffer itu tidak tersedia sebagai berikutgrep
.Anda dapat melihat masalah buffering dengan lebih jelas dengan menggunakan beberapa contoh yang memberi nomor pada garis keluaran sehingga Anda dapat mengetahui baris mana yang hilang:
Cara sederhana untuk melihat masalah buffering adalah menggunakan
seq
yang menghasilkan daftar angka. Kami dapat dengan mudah mengetahui nomor mana yang hilang:Solusi trik saya menggunakan shell untuk membaca dan mengulangi baris pertama bekerja dengan benar bahkan dengan penundaan tidur ditambahkan:
Di bawah ini adalah contoh lengkap yang menunjukkan
head
masalah buffering, menunjukkan bagaimanahead
mengkonsumsi seluruh buffer output hanya untuk menghasilkan lima barisnya setiap kali. Buffer yang dikonsumsi tidak tersedia untukhead
perintah berikutnya dalam urutan:Melihat angka di
1861
atas, kita dapat menghitung ukuran buffer yang digunakanhead
dengan menghitungseq
output dari1
ke1860
:Kita melihat bahwa
head
buffering dengan membaca 8KB penuh (8 * 1024 byte) dari output pipa pada suatu waktu, bahkan untuk menghasilkan hanya beberapa baris output sendiri.sumber