どうすれば達成できますか
cmd >> file1 2>&1 1>>file2
つまり、stdout and stderrは1つのファイル(file1)にリダイレクトし、stdout(file2)のみを別のファイルにリダイレクトする必要があります(両方とも追加モード)?
問題は、出力をリダイレクトすると、次のリダイレクトで使用できなくなることです。サブシェルでtee
にパイプして、2番目のリダイレクトの出力を保持できます。
( cmd | tee -a file2 ) >> file1 2>&1
またはターミナルで出力を見たい場合:
( cmd | tee -a file2 ) 2>&1 | tee -a file1
最初のtee
のstderrをfile1
に追加しないようにするには、コマンドのstderrをいくつかのファイル記述子(例:3)にリダイレクトし、後でこれを再度stdoutに追加する必要があります。
( 2>&3 cmd | tee -a file2 ) >> file1 3>&1
# or
( 2>&3 cmd | tee -a file2 ) 3>&1 | tee -a file1
(@ fra-sanに感謝)
zsh
の場合:
cmd >& out+err.log > out.log
追加モードの場合:
cmd >>& out+err.log >> out.log
zsh
で提供され、mult_ios
オプションは無効化されていません。ファイル記述子(ここでは1)が書き込みのために数回リダイレクトされると、シェルは組み込みtee
を実装して、すべてのターゲットに出力を複製します。
Stdoutにタグを付けることができます(UNBUFFERED sedを使用します:sed -u ...
)、stderrもstdout(タグ付けされたsedを通過しなかったため、タグ付けされていない)に移動し、結果のログファイルで2を区別できるようにします。
以下はis slow(たとえば、whileの代わりにPerlスクリプトを使用することにより、真剣に最適化できます...; do ...; done、たとえば、サブシェルとコマンドを生成しますすべての行で!)、weird(1つの名前変更stdoutに2つの{}ステージが必要であるように思われ、他の1つでは「フォールスルーされた」stderrをそれに追加します)など。 is:a "proof of concept"、これは出力の順序を可能な限りstdoutとstderrにできるだけ維持しようとします:
#basic principle (some un-necessary "{}" to visually help see the layers):
# { { complex command ;} | sed -e "s/^/TAGstdout/" ;} 2>&1 | read_stdin_and_redispatch
#exemple:
# complex command = a (slowed) ls of several things (some existing, others not)
# to see if the order of stdout&stderr is kept
#preparation, not needed for the "proof of concept", but needed for our specific exemple setup:
\rm out.file out_AND_err.file unknown unknown2
touch existing existing2 existing3
#and the (slow, too many execs, etc) "proof of concept":
uniquetag="_stdout_" # change this to something unique, that will NOT appear in all the commands outputs...
# avoid regexp characters ("+" "?" "*" etc) to make it easy to remove with another sed later on.
{
{ for f in existing unknown existing2 unknown2 existing3 ; do ls -l "$f" ; sleep 1; done ;
} | sed -u -e "s/^/${uniquetag}/" ;
} 2>&1 | while IFS="" read -r line ; do
case "$line" in
${uniquetag}*) printf "%s\n" "$line" | tee -a out_AND_err.file | sed -e "s/^${uniquetag}//" >> out.file ;;
*) printf "%s\n" "$line" >> out_AND_err.file ;;
esac;
done;
# see the results:
grep "^" out.file out_AND_err.file
出力の順序が次のようでなければならない場合:stdout then stderr;リダイレクトのみのソリューションはありません。
stderrは一時ファイルに保存する必要があります
_cmd 2>>file-err | tee -a file1 >>file2
cat file-err >> file1
rm file-err
_
説明:
one出力(stdoutまたはstderrのようなfd)をtwoファイルにリダイレクトする唯一の方法は、それを再現することです。コマンドtee
は、ファイル記述子の内容を再現するための正しいツールです。したがって、2つのファイルに1つの出力を持つという最初のアイデアは、次のようにすることです。
_... | tee file1 file2
_
これにより、ティーのstdinが両方のファイル(1と2)に再現され、ティーの出力は未使用のままになります。しかし、追加する必要があります(_-a
_を使用)。コピーは1つだけ必要です。これは両方の問題を解決します:
_... | tee -a file1 >>file2
_
tee
にstdout(繰り返すもの)を提供するには、コマンドから直接stderrを使用する必要があります。 1つの方法として、順序が重要でない場合(出力の順序は(おそらく)生成されたまま保持されますが、最初に出力された方が最初に格納されます)。どちらか:
cmd 2>>file1 | tee -a file2 >>file1
_cmd 2>>file1 > >( tee -a file2 >>file1 )
( cmd | tee -a file2 ) >> file1 2>&1
_オプション2は一部のシェルでのみ機能します。オプション3では、追加のサブシェル(低速)を使用しますが、ファイル名は1回だけ使用します。
ただし、stdoutmustが最初である場合(出力が生成される順序にかかわらず)、stderrを格納して、終了(最初のソリューションが投稿されました)。
多様性のために:
システムが/dev/stderr
をサポートしている場合、
(cmd | tee -a /dev/stderr) 2>> file1 >> file2
働くでしょう。 cmd
の標準出力は、パイプラインのstdoutとstderrの両方に送信されます。 cmd
の標準エラーはtee
をバイパスし、パイプラインのstderrから出力されます。
そう
cmd
のstdoutであり、cmd
のstdoutとstderrが混在しています。そうすれば、これらのストリームを正しいファイルに送信するだけで済みます。
このようなほとんどすべてのアプローチと同様( Stéphane’s answer を含む)、file1
は行が乱れる場合があります。