端末に表示しながら、toのtee
出力(STDOUT
)を書き込む方法を知っています。aaa.sh
bbb.out
./aaa.sh | tee bbb.out
表示したまま、STDERR
という名前のファイルに書き込むにはどうすればよいccc.out
ですか?
端末に表示しながら、toのtee
出力(STDOUT
)を書き込む方法を知っています。aaa.sh
bbb.out
./aaa.sh | tee bbb.out
表示したまま、STDERR
という名前のファイルに書き込むにはどうすればよいccc.out
ですか?
回答:
端末でSTDERRとSTDOUTを引き続き表示したいと思います。あなたはジョシュ・ケリーの答えに行くことができますが、私はtail
あなたのログファイルを出力するバックグラウンドで周りを非常にハッキーで無愛想に保つと思います。exra FDを維持し、後でkillしてクリーンアップを行う必要があることに注意してくださいtrap '...' EXIT
。技術的にはで行う必要があります。
これを行うためのより良い方法があり、すでにそれを発見しました:tee
。
ただ、それをstdoutに使用する代わりに、stdoutとtderrにT型を使用します。これをどのように達成しますか?プロセスの置換とファイルのリダイレクト:
command > >(tee -a stdout.log) 2> >(tee -a stderr.log >&2)
それを分割して説明しましょう:
> >(..)
>(...)
(プロセス置換)FIFOを作成し、それを待機させますtee
。次に、>
(ファイルリダイレクト)を使用しcommand
て、最初のSTDOUTをFIFO にリダイレクトします。tee
がリッスンし。
2番目も同じです。
2> >(tee -a stderr.log >&2)
プロセス置換を再度使用tee
して、STDINから読み取り、それをにダンプするプロセスを作成しますstderr.log
。 tee
入力をSTDOUTに出力しますが、その入力はSTDERRなので、tee
のSTDOUTを再びSTDERR にリダイレクトします。次に、ファイルリダイレクトを使用してcommand
のSTDERRをFIFOの入力(tee
のSTDIN)にます。
見る http://mywiki.wooledge.org/BashGuide/InputAndOutputをください
プロセスの置換はbash
、シェルsh
(POSIXやBourne)とは対照的に、シェルとして選択することのボーナスとして得られる本当に素敵なものの1つです。
では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"
$ echo "HANG" > >(tee stdout.log) 2> >(tee stderr.log >&2)
動作しますが、入力を待ちます。これが起こる単純な理由はありますか?
/bin/bash 2> err
して/bin/bash -i 2> err
(echo "Test Out";>&2 echo "Test Err") > >(tee stdout.log) 2> >(tee stderr.log >&2)
なぜ単純ではないのですか?
./aaa.sh 2>&1 | tee -a log
これは単ににリダイレクトされるstderr
ためstdout
、Teeはログと画面の両方にエコーします。他の解決策のいくつかは本当に複雑に見えるので、私は何かが足りないかもしれません。
注: bashバージョン4以降|&
、以下の略語として使用できます2>&1 |
。
./aaa.sh |& tee -a log
./aaa.sh |& tee aaa.log
(bashで)機能します。
set -o pipefail
が続く;
か&&
どうかは間違っていません。
これはグーグルを介してこれを見つける人々のために役立つかもしれません。試してみたい例のコメントを外してください。もちろん、出力ファイルの名前は自由に変更してください。
#!/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}
exec >
つまり、ファイル記述子のターゲットを特定の宛先に移動します。デフォルトは1なので、exec > /dev/null
このセッションでは、stdoutの出力を/ dev / null に移動します。このセッションの現在のファイル記述子は、を実行して確認できますls -l /dev/fd/
。それを試してみてください!次にexec 2>/tmp/stderr.log.
、発行時に何が起こるかを確認します。さらに、exec 3>&1
番号3の新しいファイル記述子を作成し、それをファイル記述子1のターゲットにリダイレクトします。例では、ターゲットはコマンドが発行されたときの画面でした。
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
つまり、1つのフィルター(tee bbb.out
)にstdoutをパイプし、別のフィルター(tee ccc.out
)にstderr をパイプする必要があります。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を使用してください。
sh
プロセスの置換が利用できないcronジョブに役立つ、の最も単純なアプローチ。
bashを使用している場合:
# 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
私の場合、スクリプトはstdoutとstderrの両方をファイルにリダイレクトするときにコマンドを実行していました。
cmd > log 2>&1
障害が発生したときに、エラーメッセージに基づいていくつかのアクションを実行するように更新する必要がありました。もちろん、dup 2>&1
を削除してスクリプトからstderrをキャプチャすることもできますが、エラーメッセージは参照用にログファイルに記録されません。@lhunathからの受け入れられた回答は同じことをするはずですが、リダイレクトstdout
しstderr
て別のファイルにリダイレクトします。
(cmd 2> >(tee /dev/stderr)) > log
上記では、ログは、両方のコピーを持つことになりますstdout
とstderr
、私はキャプチャすることができますstderr
気にすることなく、私のスクリプトからstdout
。
以下は、プロセス置換が利用できないKornShell(ksh)で機能します。
# create a combined(stdin and stdout) collector
exec 3 <> combined.log
# stream stderr instead of stdout to tee, while draining all stdout to the collector
./aaa.sh 2>&1 1>&3 | tee -a stderr.log 1>&3
# cleanup collector
exec 3>&-
ここでの本当のトリックは、2>&1 1>&3
私たちのケースではstderr
をstdout
にリダイレクトし、stdout
を記述子にリダイレクトするシーケンスです3
。この時点stderr
でstdout
はまだ結合されていません。
実際、stderr
(としてstdin
)はtee
、ログの記録先に渡されますstderr.log
記述子3にもリダイレクトされます。
そして記述子3
はcombined.log
常にそれを記録しています。だから、combined.log
両方が含まstdout
とstderr
。
あなたが使用している場合のzshをあなたも必要ありませんので、あなたは、複数のリダイレクトを使用することができますtee
:
./cmd 1>&1 2>&2 1>out_file 2>err_file
ここでは、単純に各ストリームをそれ自体とターゲットファイルにリダイレクトしています。
完全な例
% (echo "out"; echo "err">/dev/stderr) 1>&1 2>&2 1>/tmp/out_file 2>/tmp/err_file
out
err
% cat /tmp/out_file
out
% cat /tmp/err_file
err
これにはMULTIOS
オプションを設定する必要があることに注意してください(これがデフォルトです)。
MULTIOS