web-dev-qa-db-ja.com

teeを使用したプロセス置換とリダイレクト

Bashで、コマンドcmdの標準出力をf.outという名前のファイルにリダイレクトし、標準エラーをf.errにリダイレクトし、teeを使用して保存するとします。コンソール印刷:

cmd 1> >(tee f.out) 2> >(tee f.err)

次に、f.outには、出力とエラー(少なくとも私のシステムでは)が含まれます。

ここで、リダイレクトの順序を変更すると、次のようになります。

cmd 2> >(tee f.err) 1> >(tee f.out)

f.outには出力のみが含まれます(f.errには両方の場合のエラーのみが含まれます)。

だから私の質問は二重です:stderrをf.outにリダイレクトする方法と、リダイレクトの順序が結果に影響するのはなぜですか?

teeを使用しないが、たとえばcatを使用する場合は、次のように注意してください。

cmd 1> >(cat>f.out) 2> >(cat>f.err)

この問題は発生しておらず、リダイレクトの順序は、予想どおり、プロセス置換なしの場合(cmd 1>f.out 2>f.err)の場合と同様に重要ではありません。

5
Glyph

リダイレクトの順序は重要です。Bashは、解釈したコマンドで見つかった順序でそれらを適用するためです。

これは意図的なものであり、> file 2>&1のようなイディオムを期待どおりに機能させることができます。つまり、stderrをstdoutと同じにすることができます。このイディオムは、「fileをstdoutに割り当ててから、stderrをstdoutと等しくする」のように機能します。これにより、stderrがstdoutと同じ値を取得するまでに、stdoutの値はfileになるため期待される結果が得られます。逆(つまり、2>&1 1> file)では、stdoutの値がstderrの値にコピーされた後に変更されるため、同じ結果は得られません。ファイル記述子は、独自の値を持ち、var1="${var2}"のように別の変数の値のコピーを取得するように作成できる通常の変数に類似していると見なすことができ、そのようなvar1var2のその後の値の変更に従わないのとよく似ています。値もしません。

それはあなたが例えばすることができるようにまた便利です。 3>&1 1>&2 2>&3-のように、ファイル記述子を同じ行でスワップします。これは、一時的な「ヘルパー」fdとしてfd 3を使用して、fds 1と2を入れ替えます。

そのため、リダイレクトは、コマンドまたはスクリプトの2つの別々の行にあるかのように、順番に実行される命令と見なすことができます。

特定のケースでは、プロセス置換も含まれ、それらも指定された順序で実行されますその時点までに表現されたリダイレクトを継承します

つまり、すべてを制限するには、次のようにします。

  1. 最初にstdoutをtee f.outを実行しているプロセスにリダイレクトします。この時点で、必要に応じて、cmdのstdoutがtee f.outのstdinに接続されます。
  2. 次に、stderrをtee f.errを実行しているプロセスにリダイレクトします。しかし、これは以前に表現されたリダイレクトに従って標準出力を継承します。つまり、tee f.outの標準入力に接続されます

したがって、tee f.errは、無邪気にそのstdoutとf.errファイルに出力することにより、cmdのエラーメッセージをtee f.outのstdinにパイプし、すべてのメッセージを受信して​​、f.outファイルとターミナルウィンドウ。

5
LL3