私はTシャツの経験があまりないので、これは非常に基本的なものではないことを願っています。

回答のいずれかを確認した後この問題奇妙な動作が発生しました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番目のコマンドは実際にこの質問を入力したときにもう一度動作し、さらに5回実行したところ、1行の結果が返されました。これは私のシステムですか? (私はtmuxでzshを実行しています)。

最後に、最初のコマンド「grep syslog」が結果として表示されないのはなぜですか?

ここで制御するにはgrepなし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

修正する: headはコマンド全体を切り捨てたように見えます(以下の回答を参照)、次のコマンドは次を返します。

ps aux | tee >(grep syslog) | head -n1
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
syslog     806

答え1

$ 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ほぼ同じ時間に始まり、両方がアイドル状態のときに同じ入力データを受け取りますが、通常、データが利用可能なときに受信されます。たとえば、次の問題が原因で「非同期」出力が発生する可能性があります。

  1. 多重化されたデータは、tee実際には他のプロセスの前に1つのプロセスに転送され、ほとんどの実装によって異なりますtee。単純なtee実装では、read一定量の入力を受け取り、writeそれを2回提供します。一度は標準出力として、一度は引数として提供します。これは、これらのターゲットの1つが最初にデータを取得することを意味します。

    ただし、パイプはバッファリングされます。これらのバッファーはそれぞれ 1 つ減らす可能性が高くなりますが、大きくすることもできます。これにより、grep他のコマンドがheadデータ(例:pedライン)を受信する前に、受信コマンドの1つが必要なすべての出力(例:pedライン)を表示できます。すべて。

  2. ただし、これらのコマンドの1つはデータを受信しますが、時間内に何も実行できず、他のコマンドがより多くのデータを受信して​​すばやく処理することもできます。

    たとえば、データが一度に 1 行ずつ送信されても​​、何をheadすべきかわからない場合(またはカーネルスケジューリングのために遅延する場合)、チャンスが発生する前に結果が表示されることがあります。デモンストレーションするには、遅延を追加してみてください。これにより、ほぼ確実に出力が最初に印刷されます。grepheadgrepheadps aux | tee >(sleep 1; head -n1) | grep sysloggrep

$ ps aux | tee >(grep syslog) | head -n1
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND

head私は入力の最初の行を受け取り、標準入力を閉じて終了するので、ここでは通常1行しか得られないと思います。teestdoutが閉じられていることを確認すると、独自のstdin(の出力)を閉じてps終了します。これは実装によって異なります。

実際にps送信される唯一のデータは最初の行(もちろん制御されるため)であり、head標準入力記述子の前後の別の行にすることもできます。headtee

2行目に現れる不一致は、タイミングによって発生します。headstdinは閉じていますが、psデータは転送され続けます。両方のイベントが正しく同期されていないため、含まれている行がまだパラメータ(コマンド)syslogになる可能性があります。これは上記の説明と同様である。teegrep

stdin / exitを閉じる前にすべての入力を待つコマンドを使用すると、この問題を完全に回避できます。たとえば、awk代わりにを使用するheadと、すべての行を読み取って処理します(出力が発生しなくても)。

ps aux | tee >(grep syslog) | awk 'NR == 1'

ただし、上記のように、行はまだ順番に表示されない場合があります。

ps aux | tee >(grep syslog) | (sleep 1; awk 'NR == 1')

あまりにも詳細な情報ではないことを願っていますが、同時に互いに対話する多くのことが起こっています。別のプロセスは同期せずに同時に実行されるため、特定の実行に対する操作が異なる場合があります。時々、基本プロセスを詳しく見て、その理由を説明するのに役立ちます。

答え2

grep syslog時期によって異なるため、必ず表示されるわけではありません。シェルパイプを使用すると、ほぼ同時にコマンドを実行します。しかし、ここで重要なのは「ほぼ」という言葉です。 grepを開始する前にすべてのプロセスのチェックが完了した後、リストpsには表示されません。システム負荷などに応じてランダムな結果が得られます。

Tシャツでも同様のことが起こります。サブシェルのバックグラウンドで実行され、grepの前後にトリガーできます。これが出力順序が一貫していない理由です。

ティーの問題は奇妙に動作します。これは一般的な方法では使用されないためです。これは引数なしで実行されます。つまり、標準入力から標準出力にデータをコピーする必要があることを意味します。ただし、標準出力はヘッダー(最初の場合)またはgrep(2番目の場合)を実行するサブシェルにリダイレクトされます。ただし、次のコマンドにもパイプされます。この場合、何が起こるかは実際には実装に依存していると思います。たとえば、私のbash 4.2.28では、サブシェルのstdinには何も記録されません。 zshは、試すたびに必要な方法で安定して動作します(psの最初の行と検索された行を印刷します)。

答え3

少しハッキング的ですが、ここで私が使用するシェル関数の形の解決策がありますpsgrep()

ヘッダー行psをにリダイレクトSTDERRしてからgrepリダイレクトしますが、それ自体で発生する「ノイズ」行を防ぐには、STDOUTまずgrepコマンド自体を削除します。grep

psgrep() { ps aux | tee >(head -1>&2) | grep -v " grep $@" | grep "$@" -i --color=auto; }

関連情報