stdoutをファイルにリダイレクトし、stdout + stderrを別のファイルにリダイレクトする方法は?


32

どうすれば達成できますか

cmd >> file1 2>&1 1>>file2

つまり、stdout stderrは1つのファイル(file1)にリダイレクトし、stdout(file2)のみが別のファイルにリダイレクトする必要があります(両方とも追加モード)。

回答:


41

問題は、出力をリダイレクトすると、次のリダイレクトで使用できなくなることです。teeサブシェルにパイプして、2番目のリダイレクトの出力を保持できます。

( cmd | tee -a file2 ) >> file1 2>&1

または、ターミナルで出力を見たい場合:

( cmd | tee -a file2 ) 2>&1 | tee -a file1

最初の標準エラー出力を追加することを避けるためにteeすることがfile1、あなたには、いくつかのファイルディスクリプタ(例えば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)


16

zsh

cmd >& out+err.log > out.log

追加モードの場合:

cmd >>& out+err.log >> out.log

zshmult_iosオプションが無効になっていない場合、ファイル記述子(ここでは1)が書き込みのために数回リダイレクトされると、シェルは組み込みを実装して、teeすべてのターゲットに出力を複製します。


ここで何out+errout意味しているのか分かりません。ファイル名?リダイレクトされるストリーム?
グロノスタジ

@gronostajコマンドは次のように見えると思いますcmd >& file1 > file2
Isaac

このソリューションは、出力が生成された順序を保持します。実際にstdoutとstderrを(この順序で)保存するには、別のアプローチが必要です。
アイザック

1
@Isaacの場合、stdout出力はパイプ(各ファイルに転送するプロセス)を通過するため、stderr出力はファイルに直接送信されるため、順序は必ずしも保持されません。いずれにしても、OPはstderrの出力をstdoutの後に出力するように要求したようには見えません。
ステファンシャゼル

3

あなたが可能性:タグの標準出力(UNBUFFEREDをSED使用して、すなわち:sed -u ...)、標準エラー出力にも(SEDそれはタグ付けを通過しなかったので、タグなし)stdoutに行くので、結果のログファイルに2を区別することができています。

以下は:で、低速(;やる...;それは真剣に代わりしばらく...のexemple Perlのスクリプトのために使用することによって、最適化することができ、すべての行でサブシェル&コマンドを産卵することを、exempleのために、やった!)、奇妙な「:など、しかし、それは(私が1つのリネーム標準出力にし、他の一つに、それにstderrを「通過falled」を追加する2 {}の段階を必要とするようだ)コンセプトの証明」、それが維持しようとします出力の順序は、可能な限り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

これを理解するのは本当に難しいです。(1)なぜこのような複雑なユースケース(ls unknown)を使用してstderrに何かを印刷するのですか? >&2 echo "error"大丈夫です。(2)tee一度に複数のファイルに追加できます。(3)どうしてcat代わりにgrep "^"?(4)stderrの出力がで始まる場合、スクリプトは失敗し_stdout_ます。(5)なぜですか?
pLumo

@RoVo:最初の2行のコメント行は、概念実証の例よりも単純なアルゴリズムを示しています。1):これls loopはstdoutとstderrの両方に出力され、混合(または代替)され、制御された順序で出力されます。そのため、stdoutのタグ付けにもかかわらず、stderr / stdoutの順序が維持されていることを確認できます2):gnu tailレギュラーテール(例:aix。)。3):grep "^"は両方のファイル名も表示します。4):これは変数によって変更できます。5。
オリビエデュラック

(1)stderrとstoutへの複数のエコーは問題ありませんが、大丈夫、重要ではありませんが、読みやすくなります。(3)同意、(4)確かですが、変数に含まれるもので始まる場合は失敗します。(5)なるほど。
pLumo

@RoVo 1)に同意します。4)の場合、変数は必要に応じてpbを非表示にするために複雑にすることができます(例:uniquetag="banaNa11F453355B28E1158D4E516A2D3EDF96B3450406...)
オリビエデュラック

1
確かに、それは非常に可能性が高いわけではありませんが、とにかく後でセキュリティの問題を引き起こす可能性があります。そして、ファイルに出力する前にその文字列を削除したいかもしれません;-)
pLumo

2

出力の順序が次のとおりでなければならない場合:stdout then stderr ; リダイレクトのみの解決策はありません。
stderrは一時ファイルに保存する必要があります

cmd 2>>file-err | tee -a file1 >>file2
cat file-err >> file1
rm file-err

説明:

1つの出力(stdoutやstderrなどのfd)を2つのファイルにリダイレクトする唯一の方法は、それを再現することです。このコマンドteeは、ファイル記述子の内容を再現するための正しいツールです。そのため、2つのファイルに1つの出力を作成する最初のアイデアは、次のものを使用することです。

... |  tee file1 file2

両方のファイル(1と2)にteeのstdinが再現され、teeの出力は未使用のままになります。ただし、追加(使用-a)する必要があり、コピーは1つだけ必要です。これにより、両方の問題が解決されます。

... | tee -a file1 >>file2

電源にtee標準出力(繰り返しに1)で我々は、コマンドのうち、標準エラー出力を直接摂取する必要があります。1つの方法として、順序が重要でない場合(出力の順序は(ほとんどの場合)生成されたままに保持され、最初に出力された方が最初に保存されます)。どちらか:

  1. cmd 2>>file1 | tee -a file2 >>file1
  2. cmd 2>>file1 > >( tee -a file2 >>file1 )
  3. ( cmd | tee -a file2 ) >> file1 2>&1

オプション2は一部のシェルでのみ機能します。オプション3は追加のサブシェル(低速)を使用しますが、ファイル名は1回のみ使用します。

ただし、stdoutを 最初にする必要がある場合(出力が生成される順序)、stderrを保存して、最後にファイルに追加する必要があります(最初のソリューションが投稿されます)。


1
または、次のようにメモリに保存しますsponge(cmd | tee -a out >> out+err) 2>&1 | sponge >> out+err
StéphaneChazelas

1

多様性のために:

システムがをサポートしている/dev/stderr場合、

(cmd | tee -a /dev/stderr) 2>> file1 >> file2

働くでしょう。の標準出力cmd は、パイプラインのstdoutとstderrの両方に送信されます。cmdバイパスの標準エラーtee は、パイプラインの標準エラーをバイパスして出てきます。

そう

  • パイプラインの標準出力はのちょうどstdoutですcmd、と
  • パイプラインのstderrは、のstdoutとstderrがcmd混在しています。

その場合、これらのストリームを正しいファイルに送信するだけです。

このようなアプローチ(Stéphaneの回答を含む)の ほとんどと同様に、file1行が乱れる可能性があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.