web-dev-qa-db-ja.com

bash stdout + stderrを1つのファイルにリダイレクトし、stderrを別のファイルにリダイレクトします

すべての出力を1つのファイルにリダイレクトし、さらにstderrを別のファイルにリダイレクトする必要があります。これは簡単にできますか?

この例の目的のための私のコマンドが次のとおりであると仮定しましょう:

php /tmp/doWork.php

以下を使用して、個別のファイルに出力を取得できます。

php /tmp/doWork.php 1> /tmp/stdout_file 2> /tmp/stderr_file

this に基づいて、私は試みました:

php /tmp/doWork.php &> /tmp/stdboth_file 2> /tmp/stderr_file

しかし、これはstdoutとstderrを/tmp/stdboth_fileに入れるだけで、/tmp/stderr_fileに書き込むことはありません。

6
Luke Cousins

zsh(およびzshのみ)とそのmultios機能を使用する場合:

your-cmd 2> stdout+stderr.log >&2 2> stderr.log

Fd 2は2回リダイレクトされるため、zshは内部teeを実装して、両方のファイルに送信します。

bash(またはBourneのようなシェル)を使用すると、次の方法でteeingを手動で実行できます。

{ your-cmd 2>&1 >&3 3>&- | tee stderr.log 3>&-; } > stderr+stdout.log 3>&1

your-cmdの終了ステータスは失われますが、zsh$pipestatus[1]にありますが、bash"${PIPESTATUS[0]}"にあります(stderr+stdout.logへのリダイレクトが失敗しなかった場合))。

your-cmdのpidを記録するには、次のようにします。

{ sh -ec 'echo "$$" > /var/run/pidfile; exec your-cmd' 2>&1 >&3 3>&- |
   tee stderr.log 3>&-; } > stderr+stdout.log 3>&1

yashを使用すると、プロセスリダイレクト機能:

your-cmd > stdout+stderr.log 2>(tee stderr.log)

(ただし、yashはそのteeコマンドの終了を待機しないため、その後次のコマンドを実行するまでにログファイルが完了しない場合があることに注意してください)。

bashzsh、およびksh93プロセス置換を使用して、同様の(および同じ警告)を行うことができます。

{ your-cmd 2> >(tee stderr.log); } > stderr+stdout.log

バックグラウンドで実行してpidを取得するには:

(exec your-cmd 2> >(tee stderr.log)) > stderr+stdout.log & pid=$!

rcの場合:

{your-cmd |[2=0] tee stderr.log} > stdout+stderr.log

rcのパイプを使用すると、パイプに接続するファイル記述子を指定できます。他のシェルでは、常に左側のコマンドのfd 1と右側のコマンドのfd0です(したがって、ファイル記述子をシフトするために、上記のfd 3で少し踊ります)。 rcは、your-cmdまたはteeのいずれかが失敗した場合に失敗を報告しますが、正確な数は失われる可能性があります。

6