すべての出力を1つのファイル、デバッグログ、およびターミナルにリダイレクトする必要があるbashファイルがあります。 stdoutとstderrの両方をデバッグにリダイレクトし、スクリプト内のすべてのコマンドについてログに記録する必要があります。
ファイル内のすべてのコマンドに2>&1 | tee -a $DEBUG
を追加したくありません。私は| tee -a $DEBUG
と暮らすことができました。
exec 2>&1
のようなものでそれを行う方法があったことを覚えています。
現在、私は次のようなものを使用しています:
#!/bin/bash
DEBUGLOG=/tmp/debug
exec 2>&1
somecommand | tee -a $DEBUGLOG
somecommand2 | tee -a $DEBUGLOG
somecommand3 | tee -a $DEBUGLOG
しかし、それは機能しません。誰かが解決策を持っていますか/原因を説明できますか?
一度に多くのコマンドをリダイレクトする解決策として:
#!/bin/bash
{
somecommand
somecommand2
somecommand3
} 2>&1 | tee -a $DEBUGLOG
元のソリューションが機能しない理由:exec 2>&1は、標準エラー出力をシェルの標準出力にリダイレクトします。これは、コンソールからスクリプトを実行すると、コンソールになります。コマンドのパイプリダイレクトは、コマンドの標準出力のみをリダイレクトします。
somecommand
の観点から見ると、その標準出力はtee
に接続されたパイプに送られ、標準エラーはリダイレクトするシェルの標準エラーと同じファイル/疑似ファイルに送られますシェルの標準出力(コンソールからプログラムを実行した場合はコンソールになります)。
それを説明する真の方法の1つは、実際に何が起こるかを確認することです。
ターミナルから実行すると、シェルの元の環境は次のようになります。
stdin -> /dev/pts/42
stdout -> /dev/pts/42
stderr -> /dev/pts/42
標準エラーを標準出力(exec 2>&1
)にリダイレクトすると、基本的に何も変更されません。しかし、スクリプトの標準出力をファイルにリダイレクトすると、次のような環境になります。
stdin -> /dev/pts/42
stdout -> /your/file
stderr -> /dev/pts/42
次に、シェル標準エラーを標準出力にリダイレクトすると、次のようになります。
stdin -> /dev/pts/42
stdout -> /your/file
stderr -> /your/file
コマンドを実行すると、この環境が継承されます。コマンドを実行してそれをteeにパイプすると、コマンドの環境は次のようになります。
stdin -> /dev/pts/42
stdout -> pipe:[4242]
stderr -> /your/file
したがって、コマンドの標準エラーは、シェルが標準エラーとして使用するものに含まれます。
コマンドの環境を実際に確認するには、/proc/[pid]/fd
を調べます。ls -l
を使用して、シンボリックリンクのコンテンツもリストします。ここでの0
ファイルは標準入力、1
は標準出力、2
は標準エラーです。コマンドがより多くのファイルを開く場合(そしてほとんどのプログラムが開く場合)、それらも表示されます。プログラムは、その標準入出力をリダイレクトまたは閉じることを選択して、0
、1
および2
を再利用することもできます。
スクリプトの先頭で次のようなexecを使用できます。
exec > >(tee "$HOME/somefile.log") 2>&1
例えば:
#!/bin/bash -
exec > >(tee "$HOME/somefile.log") 2>&1
echo "$HOME"
echo hi
date
date +%F
echo bye 1>&2
次のように、ファイル$HOME/somefile.log
およびターミナルに出力を提供します。
/home/saml
hi
Sun Jan 20 13:54:17 EST 2013
2013-01-20
bye
Stderrおよびstdoutをファイルに書き込み、stderrを画面に表示します(stdout上)
exec 2> >(tee -a -i "$HOME/somefile.log")
exec >> "$HOME/somefile.log"
Cronに役立つため、メールでエラー(エラーのみ)を受け取ることができます