標準エラー出力をファイルに落としたい (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