stdoutとstderrをログファイルにコピーし、スクリプト自体のコンソールに残します。


11

bashを使用して、stderrとstdoutをログファイルにコピーし、コンソールに表示したままにするにはどうすればよいですか?

execを使用して、スクリプト自体の中でこれを実行したいと思います。

私が試した

exec &>> log.out

echo "This is stdout"
echo "This is stderr" >&2

しかし、上記はコンソールに何も出力しません。どうすればこれをbashで実現できますか?


StackOverflowの同様の質問に対する非常に賛成の回答があり、この質問に完全に答えます。stackoverflow.com/a/692407/208257
Dan Burton

回答:


10

あなたが探していteeます。

詳細man teeについては、を参照してください。

と組み合わせるにはexecプロセス置換を使用する必要があります。(詳細はman bashを参照してください。)

exec &> >(tee  log.out)
echo "This is stdout"
echo "This is stderr" >&2

私はそれを見てきました。行うexec 2>&1 | tee -a log.outだけでは、コンソール上のログファイルには何も出力しません。多分私は正しい構文を使用していませんか?
adarshr

@adarshrコードを再確認してください。プロセス置換teeと組み合わせて書きました。
H.-Dirk Schmitt

1
これはstdoutとstderrをマージしますが、私の回答で述べたのと同じ種類の副作用が発生する可能性があります。
ステファンChazelas

@StephaneChazelas質問のサンプルコードを見てください-それはOPの意図でした。
H.-Dirk Schmitt

私は何を意味でマージすることになりましたスクリプトのエラーがstdoutに行くということです。したがってthe-script | wc -l、たとえば誰かがそうした場合、エラー行もカウントされ、エラーは表示されません。
ステファンChazelas

5

できるよ:

: > log # empty log file if necessary
{ { {

  ...the script

} 3>&- | tee -a log >&3 3>&-
exit "${PIPESTATUS[0]}"
} 2>&1 | tee -a log >&2 3>&-
} 3>&1
exit "${PIPESTATUS[0]}"

次のように書くこともできます。

: > log # empty log file if necessary
exec 2> >(tee -a log >&2) > >(tee -a log)

...the script

しかし、bashは>(...)で始まるプロセスを待機していないため、コマンドが返された後、端末に「tostop」属性があると、さらに厄介な効果(出力を静かに破棄するなど)になる可能性がある何かを端末に出力するという厄介な影響があります。オンです。

いずれの場合でもstdout、両方のソリューションでパイプを作成することにより、2つのコマンドが独立して出力メッセージとエラーメッセージを出力するため、これは出力バッファリングと、出力メッセージとエラーメッセージの表示順序に影響します。


私はあなたの2番目のティーにstderrへのリダイレクトがないと思います。これは以下のようになりますtee -a log >&2 3>&-
richvdh

5

私はこれが古い投稿であることを知っていますが、なぜこれをしないのですか?

echo "hi" >> log.txt #stdout -> log
echo "hi" | tee -a log.txt #stdout -> log & stdout
echo "hi" &>> log.txt #stdout & stderr -> log
echo "hi" |& tee -a log.txt #stdout & stderr -> log & stdout

もちろん、標準出力が必要な場合は、定期的に印刷することもできます。

これは、これら2つの基本的なコマンドを使用するだけで、ストリームの任意の組み合わせで実行できます。

私がここに来て、理解/実装するのが簡単な答えが得られなかったことを知っています。うまくいけば、これは苦労している他の誰かの助けになるでしょう。

ちなみに、以前の自分のようなnoobsの場合、teeコマンドが行うことは、stdin入力をstdoutと後続の引数として指定されたファイルの両方に出力することだけです。-a追加の略なので、コマンドを使用するたびにファイルが上書きされることはありません。さらにご質問がありましたら、私が見つけ、これはすぐにはbashを学習するための非常に有用資源であることを。


1
貢献してくれてありがとう。一方、私がやろうとしていたことを完全に忘れてしまいました:-)
adarshr

1
+1は、複数の素敵でシンプルなT字の例を示します。
ティム

2

これを行うもう1つの方法は、関数内でリダイレクトを使用することです。

#!/bin/bash

function1 () {
    echo 'STDOUT from function 1'
    echo 'STDERR from function 1' >&2
}

function2 () {
    echo 'STDOUT from function 2'
    echo 'STDERR from function 2' >&2
}


function3 () {
    echo 'STDOUT from function 3'
    echo 'STDERR from function 3' >&2
}

main() {
    function1
    function2
    function3
}

main 2>&1 |tee log.txt

ここには、main他のすべての関数を呼び出す関数があります。リダイレクトSTDOUTしてSTDERRmain関数をに変更しteeます。


私見これは、少なくとも単純なケースでは、これを行う最もクリーンな方法です。ありがとう。
ACK_stoverflow 16
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.