execを使用して後続のすべてのコマンドのstderrをリダイレクトします


43

すべての出力を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

しかし、それは機能しません。誰かが解決策を持っていますか/原因を説明できますか?


1
一部のシェルで|&は、のショートカットとして機能し、2>&1 |少なくとも少し便利です。
ケビン

回答:


39

一度に多くのコマンドをリダイレクトするソリューションについて:

#!/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標準エラーです。コマンドがさらにファイルを開くと(そしてほとんどのプログラムが開きます)、それらも表示されます。プログラムはまた、標準入力/出力と再利用をリダイレクトするか、終了することができます012


41

スクリプトの上部で次のように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

2
これはbashismsを使用していることに注意してください-他のシェル(ダッシュなど)では機能しない場合があります。しかし、質問はbashを指定しているため、+ 1。
リチャードハンセン

8
@RichardHansen、プロセス置換は、bashではなくkshで導入された機能であり、zshでもサポートされているため、bashismとは呼びません。
ステファンシャゼル

6
@StephaneChazelas:あなたは良い点を挙げています。構文がPOSIX標準でサポートされていないため、/bin/shスクリプトで普遍的に機能しないことを指摘したかっただけです(多くの人が誤って/bin/shスクリプトでbash構文を使用しています)。
リチャードハンセン

私にとってこれは/dev/fd/62: Operation not supported手がかりを与えますか?
ウン

1
ログファイル以外にstderrをリダイレクトしない方法はありますか?元のスクリプトがmyscriptあり、私が実行する./myscript > /dev/nullなら、私はまだbyeどのから来るか見るべきecho bye >&2です。
マーティンJambon

0

stderrとstdoutをファイルに書き込み、画面にstderrを表示します(stdoutで)

exec 2> >(tee -a -i "$HOME/somefile.log")
exec >> "$HOME/somefile.log"

cronに便利です。メールでエラー(およびエラーのみ)を受信できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.