私はティーの使用経験があまりないので、これはあまり基本的なことではないと思います。
この質問への回答の1つを表示した後tee
で奇妙な動作に遭遇しました。
最初の行と見つかった行を出力するために、これを使用できます。
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
ただし、これを(zshで)初めて実行したときの結果は間違った順序であり、列ヘッダーはgrepの結果の下にありました(ただし、これは再び発生しませんでした)。したがって、コマンドを入れ替えてみました。
ps aux | tee >(grep syslog) | head -n1
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
最初の行だけが印刷され、それ以外は何も印刷されません。 teeを使用してgrepにリダイレクトできますか、それとも間違った方法で行っていますか?
この質問を入力していると、2番目のコマンドは実際には1回だけ機能し、5回実行してから1行目の結果に戻りました。これは私のシステムですか? (私はtmux内でzshを実行しています)。
最後に、最初のコマンドで「grep syslog」が結果として表示されないのはなぜですか(結果は1つだけです)?
ここでの制御は、tee
なしのgrepです。
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
更新:ヘッドがコマンド全体を切り捨てているようです(以下の回答で示されているように)、以下のコマンドは次を返します:
ps aux | tee >(grep syslog) | head -n1
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
syslog 806
_$ 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
_
grep
コマンドとhead
コマンドはほぼ同時に開始され、どちらも自分の都合の良いときに同じ入力データを受け取りますが、一般的には、データが使用可能になったときです。行を反転させる「非同期」出力を導入する可能性のあるいくつかのものがあります。例えば:
tee
の多重化されたデータは、主にtee
の実装に応じて、実際には1つのプロセスに送られます。単純なtee
の実装は、ある程度の入力をread
してから、それを2回write
します。つまり、これらの宛先の1つが最初にデータを取得します。
ただし、パイプはすべてバッファリングされます。これらのバッファーはそれぞれ1行である可能性が高いですが、バッファーが大きくなる可能性があり、受信コマンドの1つが他のコマンド(grep
)がデータを受信する前に、出力に必要なすべて(つまり、head
ped行)を表示する可能性がありますまったく。
上記にかかわらず、これらのコマンドの1つがデータを受信しても、間に合うようにデータを処理できず、他のコマンドがより多くのデータを受信して迅速に処理する可能性もあります。
たとえば、head
とgrep
が一度に1行ずつデータを送信されたとしても、head
がその対処方法を知らない場合(またはカーネルスケジューリングによって遅延される場合)、grep
がhead
の前に結果を表示して、 。実例として、遅延を追加してみてください:ps aux | tee >(sleep 1; head -n1) | grep syslog
これにより、ほぼ確実にgrep
出力が最初に出力されます。
_$ ps aux | tee >(grep syslog) | head -n1
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
_
head
は入力の最初の行を受け取ってから、そのstdinを閉じて終了するため、ここでは1行しか得られないことが多いと思います。 tee
は、stdoutが閉じていることを確認すると、自身のstdin(ps
からの出力)を閉じて終了します。これは実装に依存する可能性があります。
事実上、ps
が送信する唯一のデータは最初の行(head
がこれを制御しているため)であり、head
&tee
の前にある他のいくつかの行がstdin記述子を閉じます。
2行目が表示されるかどうかの不一致は、タイミングによって発生します。head
はstdinを閉じますが、ps
はまだデータを送信しています。これら2つのイベントは十分に同期されていないため、syslog
を含む行は、tee
の引数(grep
コマンド)に到達する可能性があります。これは上記の説明に似ています。
Stdin/exitを閉じる前にすべての入力を待つコマンドを使用することで、この問題を完全に回避できます。たとえば、awk
の代わりにhead
を使用します。これにより、すべての行が読み取られて処理されます(出力が発生しない場合でも)。
_ps aux | tee >(grep syslog) | awk 'NR == 1'
_
ただし、上記のように、線が順不同で表示される可能性があることに注意してください。
_ps aux | tee >(grep syslog) | (sleep 1; awk 'NR == 1')
_
これがあまり詳細ではなかったことを願っていますが、相互に作用し合う同時のものがたくさんあります。個別のプロセスは同期せずに同時に実行されるため、特定の実行に対するアクションは異なる場合があります。根本的なプロセスを深く掘り下げて理由を説明することが役立つ場合があります。
grep syslog
はタイミングに依存するため、常に表示されるとは限りません。シェルパイプラインを使用すると、ほぼ同時にコマンドが実行されます。しかし、ここで重要なのは「ほぼ」という言葉です。 ps
がgrepを起動する前にすべてのプロセスのスキャンを終了した場合、そのプロセスはリストに含まれません。システムの負荷などに応じてランダムな結果を得ることができます。
Tシャツでも同様のことが起こります。サブシェルのバックグラウンドで実行され、grepの前または後に起動されます。これが、出力順序に一貫性がない理由です。
T字の質問については、その動作はかなり奇妙です。これは、通常の方法では使用されないためです。引数なしで実行されます。つまり、stdinからstdoutにデータをコピーするだけです。しかし、それは標準出力がヘッド(最初のケース)またはgrep(2番目のケース)を実行しているサブシェルにリダイレクトされます。しかし、次のコマンドにもパイプされます。この場合に起こることは、実際には実装に依存していると思います。たとえば、私のbash 4.2.28では、サブシェルstdinに何も書き込まれません。 zshでは、希望する方法で信頼性の高い動作をします(psの最初の行と検索された行の両方を出力します)。
少しハッキリですが、これが私の解決策です。使用するpsgrep()
シェル関数の形式で:
ps
ヘッダー行をSTDERR
にリダイレクトし、次にgrep
をSTDOUT
にリダイレクトしますが、最初にgrep
コマンド自体を削除して、「 grep
自体に起因するノイズ」行:
psgrep() { ps aux | tee >(head -1>&2) | grep -v " grep $@" | grep "$@" -i --color=auto; }