ターミナルに表示しながら、 toの出力 (標準出力)tee
を書き込む方法を知っています。aaa.sh
bbb.out
./aaa.sh | tee bbb.out
という名前のファイルに標準エラーを表示しながら、標準エラーを書き込むにはどうすればよいですか?ccc.out
端末で STDERR と STDOUT を引き続き表示したいと思っていると思います。Josh Kelley の答えに行くこともできますがtail
、バックグラウンドでログ ファイルを出力するのは非常にハックでぎこちないことがわかりました。exra FD を保持し、後でそれを強制終了してクリーンアップを行う必要があることに注意してください。技術的には、trap '...' EXIT
.
これを行うためのより良い方法があり、あなたはすでにそれを発見しています: tee
.
stdout に使用するだけでなく、stdout 用のティーと stderr 用のティーを用意してください。これをどのように達成しますか?プロセスの置換とファイルのリダイレクト:
command > >(tee -a stdout.log) 2> >(tee -a stderr.log >&2)
それを分割して説明しましょう:
> >(..)
>(...)
(プロセス置換) は FIFO を作成し、tee
それをリッスンします。次に、>
(ファイル リダイレクト) を使用して、STDOUT を最初にリッスンしてcommand
いる FIFOにリダイレクトします。tee
2 番目の同じこと:
2> >(tee -a stderr.log >&2)
再びプロセス置換を使用してtee
、STDIN から読み取って にダンプするプロセスを作成しますstderr.log
。 はその入力を STDOUT に出力しますが、その入力は STDERR であるため、の STDOUT を STDERR に再度tee
リダイレクトしたいと考えています。tee
次に、ファイル リダイレクトを使用command
して、 の STDERR を FIFO の入力 (tee
の STDIN) にリダイレクトします。
http://mywiki.wooledge.org/BashGuide/InputAndOutputを参照してください。
プロセス置換は、 (POSIX または Bourne)bash
とは対照的に、シェルとして選択することのボーナスとして得られる、本当に素晴らしいものの 1 つです。sh
ではsh
、次のことを手動で行う必要があります。
out="${TMPDIR:-/tmp}/out.$$" err="${TMPDIR:-/tmp}/err.$$"
mkfifo "$out" "$err"
trap 'rm "$out" "$err"' EXIT
tee -a stdout.log < "$out" &
tee -a stderr.log < "$err" >&2 &
command >"$out" 2>"$err"
単に:
./aaa.sh 2>&1 | tee -a log
これは単に標準エラーを標準出力にリダイレクトするため、teeはログと画面の両方にエコーします。他の解決策のいくつかは本当に複雑に見えるので、たぶん私は何かが欠けています。
注: Bashバージョン4以降、次|&
の略語として使用できます2>&1 |
。
./aaa.sh |& tee -a log
これは、Google 経由でこれを見つけた人に役立つかもしれません。試してみたいサンプルのコメントを外してください。もちろん、出力ファイルの名前は自由に変更してください。
#!/bin/bash
STATUSFILE=x.out
LOGFILE=x.log
### All output to screen
### Do nothing, this is the default
### All Output to one file, nothing to the screen
#exec > ${LOGFILE} 2>&1
### All output to one file and all output to the screen
#exec > >(tee ${LOGFILE}) 2>&1
### All output to one file, STDOUT to the screen
#exec > >(tee -a ${LOGFILE}) 2> >(tee -a ${LOGFILE} >/dev/null)
### All output to one file, STDERR to the screen
### Note you need both of these lines for this to work
#exec 3>&1
#exec > >(tee -a ${LOGFILE} >/dev/null) 2> >(tee -a ${LOGFILE} >&3)
### STDOUT to STATUSFILE, stderr to LOGFILE, nothing to the screen
#exec > ${STATUSFILE} 2>${LOGFILE}
### STDOUT to STATUSFILE, stderr to LOGFILE and all output to the screen
#exec > >(tee ${STATUSFILE}) 2> >(tee ${LOGFILE} >&2)
### STDOUT to STATUSFILE and screen, STDERR to LOGFILE
#exec > >(tee ${STATUSFILE}) 2>${LOGFILE}
### STDOUT to STATUSFILE, STDERR to LOGFILE and screen
#exec > ${STATUSFILE} 2> >(tee ${LOGFILE} >&2)
echo "This is a test"
ls -l sdgshgswogswghthb_this_file_will_not_exist_so_we_get_output_to_stderr_aronkjegralhfaff
ls -l ${0}
stderr をファイルにリダイレクトするには、stdout を画面に表示し、stdout をファイルに保存します。
./aaa.sh 2>ccc.out | ティー/bbb.out
編集: stderr と stdout の両方を画面に表示し、両方をファイルに保存するには、bash のI/O リダイレクトを使用できます。
#!/bin/bash
# Create a new file descriptor 4, pointed at the file
# which will receive stderr.
exec 4<>ccc.out
# Also print the contents of this file to screen.
tail -f ccc.out &
# Run the command; tee stdout as normal, and send stderr
# to our file descriptor 4.
./aaa.sh 2>&4 | tee bbb.out
# Clean up: Close file descriptor 4 and kill tail -f.
exec 4>&-
kill %1
つまり、stdout を 1 つのフィルター ( tee bbb.out
) にパイプし、stderr を別のフィルター ( tee ccc.out
) にパイプします。stdout 以外のものを別のコマンドにパイプする標準的な方法はありませんが、ファイル記述子をジャグリングすることで回避できます。
{ { ./aaa.sh | tee bbb.out; } 2>&1 1>&3 | tee ccc.out; } 3>&1 1>&2
標準エラー ストリーム (stderr) を grep する方法も参照してください。いつ追加のファイル記述子を使用しますか?
bash (および ksh と zsh) ではプロセス置換を使用できますが、dash などの他の POSIX シェルでは使用できません。
./aaa.sh > >(tee bbb.out) 2> >(tee ccc.out)
bash では./aaa.sh
、コマンドがまだ実行されている場合でも、このコマンドは終了するとすぐに戻ることに注意してくださいtee
(ksh と zsh はサブプロセスを待機します)。のようなことをすると、これが問題になることがあります./aaa.sh > >(tee bbb.out) 2> >(tee ccc.out); process_logs bbb.out ccc.out
。その場合は、代わりにファイル記述子ジャグリングまたは ksh/zsh を使用してください。
バッシュを使用する場合:
# Redirect standard out and standard error separately
% cmd >stdout-redirect 2>stderr-redirect
# Redirect standard error and out together
% cmd >stdout-redirect 2>&1
# Merge standard error with standard out and pipe
% cmd 2>&1 |cmd2
クレジット (頭のてっぺんからの回答ではありません) は次のとおりです: http://www.cygwin.com/ml/cygwin/2003-06/msg00772.html
以下は、プロセス置換が利用できない KornShell (ksh) で機能します。
# create a combined (standard input and standard output) collector
exec 3 <> combined.log
# stream standard error instead of standard output to tee, while draining all standard output to the collector
./aaa.sh 2>&1 1>&3 | tee -a stderr.log 1>&3
# cleanup collector
exec 3>&-
ここでの本当のトリックは2>&1 1>&3
、標準エラーを標準出力にリダイレクトし、標準出力をファイル記述子3 にリダイレクトするシーケンスです。この時点では、標準エラーと標準出力はまだ結合されていません。
tee
実際には、標準エラー (標準入力として) は、ログが記録される場所に渡され、stderr.log
ファイル記述子 3 にもリダイレクトされます。
そして、ファイル記述子 3 は常にログに記録してcombined.log
います。したがって、combined.log
標準出力と標準エラーの両方が含まれます。
私の場合、スクリプトは stdout と stderr の両方をファイルにリダイレクトしながらコマンドを実行していました。
cmd > log 2>&1
障害が発生した場合に、エラー メッセージに基づいて何らかのアクションを実行できるように更新する必要がありました。もちろん、dup2>&1
を削除してスクリプトから stderr をキャプチャすることもできますが、エラー メッセージは参照用のログ ファイルに記録されません。@lhunathからの受け入れられた回答は同じことをするはずですが、リダイレクトstdout
しstderr
て別のファイルにリダイレクトしますが、これは私が望むものではありませんが、必要な正確な解決策を思いつくのに役立ちました:
(cmd 2> >(tee /dev/stderr)) > log
stdout
上記の場合、ログにはとの両方のコピーが含まれ、.を気にせずにスクリプトからstderr
キャプチャできます。stderr
stdout