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

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

どうやって達成できますか?

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

つまり、標準出力そしてstderrは1つのファイル(ファイル1)にリダイレクトする必要があり、stdout(ファイル2)のみを別のファイルにリダイレクトする必要があります(どちらも追加モードで)。

答え1

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

( 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に感謝します)

答え2

そしてzsh

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

追加モードでは:

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

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

答え3

次のことができます。 stdoutを表示し(つまりsed -u ...:)、stderrもstdoutに移動し(sedマークを通過しないため表示されません)、生成されたログファイルから2を区別できます。

次のように:はい遅い(たとえば、while ...; do ...; doneの代わりにperlスクリプトを使用すると、真剣に最適化される可能性があります。たとえば、すべての行にサブシェルとコマンドが生成されます!)奇妙な(あるステップでstdoutの名前を変更し、別のステップで「失敗」stderrを追加するには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

答え4

多様性のため:

あなたのシステムがそれをサポートしているなら/dev/stderr

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

動作します。標準出力はcmd stdout および stderr パイプに送信されます。標準エラーはパイプされたstderrをcmdバイパスしますtee

だから

  • パイプの標準出力はパイプcmdの標準出力にすぎません。
  • パイプの stderr はcmdstdout と stderr の混合です。

その後、これらのストリームを正しいファイルに送信するのは簡単です。

ほぼすべての同様の方法(含む)と同様にスティーブンの答え)、 file1これは線が正しく機能しない可能性があります。

関連情報