標準エラー出力をファイルに落としたい (teeの標準エラー出力版)
tee
というコマンドがあります。
「標準入力から読んだ内容を標準出力とファイルに書きだす」というものです。
例えば、
$ foo | tee logfile
とすると、 foo
コマンドの標準出力は、 logfile
に書き出されます。
なおかつ、標準出力は標準出力として、標準エラー出力は標準エラー出力として出力されます。
ログを記録するときには便利なコマンドですね。
そこで思ったのは、 tee
コマンドの標準エラー版に相当するものを実現できないかと思いました。
コンパイルのときの warning とかは通常、標準エラー出力へ出てきます。
標準エラー出力をファイルに記録しておいて、 warning を潰していくのに使いたいのです。
で、考えたシェルスクリプトが以下です。
#!/bin/sh
exec 3>&1
foo 2>&1 >&3 3>&- | tee logfile >&2
foo
コマンドの標準エラー出力を logfile
に書き出します。
なおかつ、標準出力は標準出力として、標準エラー出力は標準エラー出力として出力されます。
m>&n
は 「n
番の出力先と同じものを m
番へコピーする (dup2
する)」という意味です。
m>&-
は 「m
番を閉じる」という意味です。
また、 exec
は引数にコマンドが与えられていない場合、リダイレクト処理はカレントシェルで効果を表します。
つまり、上記のスクリプトは、 foo
コマンドの標準出力と標準エラー出力を入れ替えて、
パイプに流し、さらに tee
コマンドの標準出力(= foo
コマンドの標準エラー出力)
を標準エラー出力に戻す、ということをしています。
(後日、bash なら foo |& tee logfile >&2
のように簡単に書けることを知った。。)
さらに、 foo
が異常終了した場合に、即座にシェルスクリプトを止めたいときは、以下のようにします。
パイプに渡してしまうと、そのままでは終了ステータスを取れませんので、ちょっと複雑になっております。。
#!/bin/sh
exec 3>&1
status=$({ { foo 2>&1 >&3 3>&- 4>&-; echo $? 1>&4 3>&- 4>&-;} | tee log >&2 3>&- 4>&- ;} 4>&1)
if [ "$status" != "0" ]; then
set -e
/bin/false
fi
bash の $PIPESTATUS
の実現方法はこちらのページで勉強させていただきました。
blog comments powered by Disqus