Saya tidak punya banyak pengalaman menggunakan tee, jadi saya harap ini tidak terlalu mendasar.
Setelah melihat salah satu jawaban untuk pertanyaan ini, saya menemukan beheviour aneh dengan tee
.
Agar saya dapat menampilkan baris pertama, dan baris yang ditemukan, saya dapat menggunakan ini:
ps aux | tee >(head -n1) | grep syslog
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
syslog 806 0.0 0.0 34600 824 ? Sl Sep07 0:00 rsyslogd -c4
Namun, pertama kali saya menjalankan ini (di zsh) hasilnya berada di urutan yang salah, header kolom berada di bawah hasil grep (ini tidak terjadi lagi), jadi saya mencoba untuk menukar perintah di sekitar:
ps aux | tee >(grep syslog) | head -n1
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
Hanya baris pertama yang dicetak, dan tidak ada yang lain! Bisakah saya menggunakan tee untuk mengarahkan ke grep, atau apakah saya melakukan ini dengan cara yang salah?
Ketika saya mengetik pertanyaan ini, perintah kedua sebenarnya bekerja sekali untuk saya, saya menjalankannya lagi lima kali dan kemudian kembali ke hasil satu baris. Apakah ini hanya sistem saya? (Saya menjalankan zsh dalam tmux).
Akhirnya, mengapa dengan perintah pertama adalah "grep syslog" tidak ditampilkan sebagai hasilnya (hanya ada satu hasil)?
Untuk kontrol di sini adalah grep tanpa tee
ps aux | grep syslog
syslog 806 0.0 0.0 34600 824 ? Sl Sep07 0:00 rsyslogd -c4
henry 2290 0.0 0.1 95220 3092 ? Ssl Sep07 3:12 /usr/bin/pulseaudio --start --log-target=syslog
henry 15924 0.0 0.0 3128 824 pts/4 S+ 13:44 0:00 grep syslog
Pembaruan: Tampaknya head menyebabkan seluruh perintah terpotong (seperti ditunjukkan dalam jawaban di bawah) perintah di bawah ini sekarang mengembalikan yang berikut:
ps aux | tee >(grep syslog) | head -n1
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
syslog 806
ps aux | sed -n -e '1p' -e '/syslog/p'
.Jawaban:
The
grep
danhead
perintah mulai di sekitar waktu yang sama, dan keduanya menerima data input yang sama di waktu luang mereka sendiri, tetapi umumnya, sebagai data menjadi tersedia. Ada beberapa hal yang dapat memperkenalkan keluaran 'tidak disinkronkan' yang membalik baris; sebagai contoh:Data multiplexed dari
tee
sebenarnya dikirim ke satu proses sebelum yang lain, terutama tergantung pada implementasitee
.tee
Implementasi sederhana akanread
sejumlah input, dan kemudianwrite
dua kali: Sekali untuk stdout dan sekali untuk argumennya. Ini berarti bahwa salah satu tujuan tersebut akan mendapatkan data terlebih dahulu.Namun, semua pipa disangga. Kemungkinan buffer ini masing-masing adalah 1 baris, tetapi mereka mungkin lebih besar, yang dapat menyebabkan salah satu dari perintah penerima untuk melihat semua yang dibutuhkan untuk output (mis.
grep
Jalur ped) sebelum perintah lainnya (head
) telah menerima data apa pun di semua.Terlepas dari hal di atas, ada juga kemungkinan bahwa salah satu dari perintah ini menerima data tetapi tidak dapat melakukan apa pun dengan waktu, dan kemudian perintah lainnya menerima lebih banyak data dan memprosesnya dengan cepat.
Sebagai contoh, bahkan jika
head
dangrep
dikirim data satu baris pada satu waktu, jikahead
tidak tahu bagaimana menghadapinya (atau tertunda oleh penjadwalan kernel),grep
dapat menunjukkan hasilnya sebelumhead
bahkan mendapat kesempatan. Untuk menunjukkan, coba tambahkan penundaan:ps aux | tee >(sleep 1; head -n1) | grep syslog
Ini hampir pasti akan mengeluarkangrep
output terlebih dahulu.Saya percaya Anda sering hanya mendapatkan satu baris di sini, karena
head
menerima input baris pertama dan kemudian menutup stdin dan keluar. Ketikatee
melihat bahwa stdout-nya telah ditutup, ia kemudian menutup stdin-nya sendiri (keluaran darips
) dan keluar. Ini bisa tergantung pada implementasi.Secara efektif, satu-satunya data yang
ps
dapat dikirim adalah baris pertama (pasti, karenahead
mengendalikan ini), dan mungkin beberapa baris lain sebelumhead
&tee
menutup deskriptor stdin mereka.Ketidakkonsistenan dengan apakah baris kedua muncul diperkenalkan oleh pengaturan waktu:
head
menutup stdin, tetapips
masih mengirim data. Kedua peristiwa ini tidak disinkronkan dengan baik, sehingga baris yang berisisyslog
masih memiliki peluang untuk membuatnya ketee
argumen (grep
perintah). Ini mirip dengan penjelasan di atas.Anda dapat menghindari masalah ini sama sekali dengan menggunakan perintah yang menunggu semua input sebelum menutup stdin / keluar. Misalnya, gunakan
awk
alih-alihhead
, yang akan membaca dan memproses semua barisnya (bahkan jika tidak ada keluaran):Tetapi perhatikan bahwa garis-garis tersebut masih dapat terlihat rusak, seperti di atas, yang dapat ditunjukkan oleh:
Semoga ini tidak terlalu detail, tetapi ada banyak hal simultan yang saling berinteraksi. Proses terpisah berjalan secara simultan tanpa sinkronisasi apa pun, sehingga tindakan mereka pada proses tertentu dapat bervariasi; terkadang membantu menggali jauh ke dalam proses yang mendasarinya untuk menjelaskan alasannya.
sumber
ps aux | tee >(grep syslog) | head -n1
yang akan berhentihead
menutup stdout. Wow, perintah ini sudah mulai memberikan hasil sekarang, tetapi seperti yang akan terjadi sesuai dengan jawaban Anda, tampaknya akan terpotongUSER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
syslog 806
head
. Saya telah memperbarui jawabannya dengan contoh ini:ps aux | tee >(grep syslog) | awk 'NR == 1'
>(cmd)
, shell membuat pipa bernama dan melewati itu sebagai argumen ke perintah (tee
). Kemudiantee
menulis ke stdout (disalurkan keawk
) dan juga untuk argumen itu. Itu sama sepertimkfifo a_fifo ; grep ... a_fifo
di satu shell danps | tee a_fifo | awk ...
di yang lain.echo >(exit 0)
, yang akan menggemakan argumen aktual yang diteruskan oleh shell (dalam kasus saya, menjadi/dev/fd/63
). Ini harus bekerja sama pada bash dan zsh.grep syslog
tidak selalu ditampilkan karena tergantung pada waktu. Saat menggunakan pipa shell, Anda menjalankan perintah hampir secara bersamaan. Tetapi kuncinya di sini adalah kata "hampir". Jikaps
selesai memindai semua proses sebelum grep diluncurkan, itu tidak akan ada dalam daftar. Anda bisa mendapatkan hasil acak tergantung pada beban sistem dll.Hal serupa terjadi dengan tee Anda. Ini dijalankan pada latar belakang dalam subkulit dan dapat dipecat sebelum atau setelah grep. Inilah sebabnya mengapa urutan output tidak konsisten.
Sedangkan untuk pertanyaan tee, perilakunya cukup aneh. Ini karena tidak digunakan dengan cara normal. Ini dijalankan tanpa argumen yang berarti harus menyalin data dari stdin ke stdout. Tapi stdout itu diarahkan ke subshell running head (dalam kasus pertama) atau grep (kasus kedua). Tetapi itu juga disalurkan ke perintah berikutnya. Saya pikir apa yang terjadi dalam kasus ini sebenarnya tergantung pada implementasi. Misalnya pada bash 4.2.28 saya, tidak ada yang pernah ditulis untuk subshell stdin. Pada zsh, ini berfungsi andal seperti yang Anda inginkan (mencetak baris pertama ps dan baris yang dicari), setiap kali saya mencoba,
sumber
Sedikit retas, tapi ini solusinya, dalam bentuk
psgrep()
fungsi shell yang saya gunakan:Arahkan ulang
ps
baris tajuk keSTDERR
, lalugrep
aktifSTDOUT
, tetapi pertama-tama hapusgrep
perintah itu sendiri, untuk menghindari baris "derau" yang berasal darigrep
dirinya sendiri:sumber