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
)の場合と同様に重要ではありません。
リダイレクトの順序は重要です。Bashは、解釈したコマンドで見つかった順序でそれらを適用するためです。
これは意図的なものであり、> file 2>&1
のようなイディオムを期待どおりに機能させることができます。つまり、stderrをstdoutと同じにすることができます。このイディオムは、「file
をstdoutに割り当ててから、stderrをstdoutと等しくする」のように機能します。これにより、stderrがstdoutと同じ値を取得するまでに、stdoutの値はfile
になるため期待される結果が得られます。逆(つまり、2>&1 1> file
)では、stdoutの値がstderrの値にコピーされた後に変更されるため、同じ結果は得られません。ファイル記述子は、独自の値を持ち、var1="${var2}"
のように別の変数の値のコピーを取得するように作成できる通常の変数に類似していると見なすことができ、そのようなvar1
はvar2
のその後の値の変更に従わないのとよく似ています。値もしません。
それはあなたが例えばすることができるようにまた便利です。 3>&1 1>&2 2>&3-
のように、ファイル記述子を同じ行でスワップします。これは、一時的な「ヘルパー」fdとしてfd 3を使用して、fds 1と2を入れ替えます。
そのため、リダイレクトは、コマンドまたはスクリプトの2つの別々の行にあるかのように、順番に実行される命令と見なすことができます。
特定のケースでは、プロセス置換も含まれ、それらも指定された順序で実行されますその時点までに表現されたリダイレクトを継承します
つまり、すべてを制限するには、次のようにします。
tee f.out
を実行しているプロセスにリダイレクトします。この時点で、必要に応じて、cmd
のstdoutがtee f.out
のstdinに接続されます。tee f.err
を実行しているプロセスにリダイレクトします。しかし、これは以前に表現されたリダイレクトに従って標準出力を継承します。つまり、tee f.out
の標準入力に接続されますしたがって、tee f.err
は、無邪気にそのstdoutとf.errファイルに出力することにより、cmd
のエラーメッセージをtee f.out
のstdinにパイプし、すべてのメッセージを受信して、f.outファイルとターミナルウィンドウ。