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
どちらの場合もエラーのみを含む)。
だから私の質問は2つです。 stderrをにどのようにリダイレクトしますかf.out
?そして、リダイレクト順序が結果に影響を与えるのはなぜですか?
を使用しない場合は、次のようになりますtee
。cat
cmd 1> >(cat>f.out) 2> >(cat>f.err)
この問題はなく、期待どおりにプロセスを交換せずにリダイレクトの順序は重要ではありません(cmd 1>f.out 2>f.err
)。
答え1
Bash は、解釈するコマンドで見つかった順序でリダイレクトを適用するため、リダイレクトの順序が重要です。
これは予想通りイディオムが機能するようにするためです> file 2>&1
。つまり、stderrをstdoutと同じにします。このイディオムは、file
「stdoutに割り当ててからstderrをstdoutと同じにする」と同じように機能します。これは、stdoutの値がstderrがstdoutと同じ値を取得したときであるため、予想される結果を生成しますfile
。他の方法(例えば2>&1 1> file
)は、stderr値をコピーした後にstdout値が変更されるため、同じ結果を生成しません。ファイルディスクリプタは独自の値を持ち、他の変数値のコピーを取得するために使用できるという点で一般変数と似ていると考えることができます。var1="${var2}"
同様に、後続の値の変更はvar1
続きません。var2
ファイル記述子もそうではありません。
また便利です。たとえば、同じ行でファイル記述子を置き換えることができます3>&1 1>&2 2>&3-
。これは、fd 3をfd 1と2を置き換える一時的な「ヘルパー」fdとして使用します。
したがって、リダイレクトは、コマンドまたはスクリプトの別々の2行にあるように、順番に実行されるコマンドと考えることができます。
特定のケースでは、プロセス置換も含まれ、指定された順序で実行されます。これまでに表現されたリダイレクトの継承
つまり、要約すると次のようになります。
- まず、stdoutを実行中のプロセスにリダイレクトします
tee f.out
。このとき、stdoutはcmd
必要に応じてtee f.out
stdinに接続されます。 - その後、stderrは実行中のプロセスにリダイレクトされますが、
tee f.err
これは前述のリダイレクトに従って標準出力、つまり接続されているtee f.out
標準入力を継承します。
したがって、stdoutファイルとf.errファイルに無害に出力し、エラーメッセージをstdinにtee f.err
パイプしてすべてのメッセージを受信し、f.outファイルとターミナルウィンドウに出力します。cmd
tee f.out
答え2
私はこの問題に直面し、これが私が実行しているテストに対する答えの一部です。このコマンドの一般的なケースは、cmdを実行して端末に表示し、stderr(インデントと赤で表示)を変更してから、画面に表示される内容をログファイルに保存することです。ログからカラーコーディングを削除します。
したがって、2つのstdout行と2つのstderr行を生成するサンプルcmdは次のようになります。
{ ls -l /usr/bin/col{1,2,a,b} 2>&1 >&3 | sed 's/.*/\t\o33[31mSTDERR: &\o33[0m/'; } 3>&1
それでは、ログファイルにコピーを入れてください。
{ ls -l /usr/bin/col{1,2,a,b} 2>&1 >&3 | sed 's/.*/\t\o33[31mSTDERR: &\o33[0m/'; } 3>&1 | tee >( sed 's/\o33//g;s/\[31m//g;s/\[0m//' > /tmp/file )
しかし、これはうまくいきます。これを達成するより良い方法はありますか?