プロセスの交換とリダイレクトにティーを使用する

プロセスの交換とリダイレクトにティーを使用する

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?そして、リダイレクト順序が結果に影響を与えるのはなぜですか?

を使用しない場合は、次のようになりますteecat

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行にあるように、順番に実行されるコマンドと考えることができます。

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

つまり、要約すると次のようになります。

  1. まず、stdoutを実行中のプロセスにリダイレクトしますtee f.out。このとき、stdoutはcmd必要に応じてtee f.outstdinに接続されます。
  2. その後、stderrは実行中のプロセスにリダイレクトされますが、tee f.errこれは前述のリダイレクトに従って標準出力、つまり接続されているtee f.out標準入力を継承します。

したがって、stdoutファイルとf.errファイルに無害に出力し、エラーメッセージをstdinにtee f.errパイプしてすべてのメッセージを受信し、f.outファイルとターミナルウィンドウに出力します。cmdtee 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 )

しかし、これはうまくいきます。これを達成するより良い方法はありますか?

関連情報