bashのpipefailで確実にスクリプトを止める
Sun Apr 26 22:27:31 JST 2015 (modified: Sun Oct 1 10:50:27 JST 2017)
views: 12465, keywords:ごめんなさい,bash,Linux,Mac,pipefail,ご報告,シェルプログラミング実用テクニック,寝る この記事は最終更新日が7年以上前のものです。
シェルプログラミング実用テクニック、出版される前からもう補足ですが、私めがbashのpipefailというオプションをすっかり見落としていたのでフォローしておきます。
- カンニング先: パイプの途中のエラーを取る | 揮発性のメモ
本文ではbashに-e(エラーがあったら止める)をつけてもパイプラインの左側のコマンドにエラーがあったときに処理が止まらないと書きました。
例です。
###false | true###でfalseが終了ステータス1を返すが・・・###
uedambp:~ ueda$ cat hoge.bash
#!/bin/bash -e
false | true
echo do not stop
###-eがあるにもかかわらずechoが実行される###
uedambp:~ ueda$ ./hoge.bash
do not stop
が、次のようにpipefailというオプションをセットしておくと(シバンの横には引数を一個しか渡せないと考えた方がよいので、下でsetを使って指定する)、次のように止まります。あらびっくり。
uedambp:~ ueda$ cat pipefail.bash
#!/bin/bash -e
set -o pipefail
false | true
echo do not stop
uedambp:~ ueda$ ./pipefail.bash
uedambp:~ ueda$ <- echoは実行されない
執筆する前にもうちょっとちゃんとmanをしっかり読んでおけよと自分に鋭いツッコミを入れましたが、bashの文法解説書というよりはコマンドの使い方解説書という感じで書いていたのでちょっと手薄になっておりました・・・。
manにはこう書いてあります。(Linuxだとmanの出力はパイプに渡せます。)
ueda@ubuntu:~$ man bash 2> /dev/null | grep -A 3 pipefail$
pipefail
0 以外のステータスで終了した最後の
設定されている場合、パイプラインの返り値は、 (一番右の) コマンドの値になります。 パイプラインの全てのコマンドが成功の状態で
0 になります。 このオプションは、デフォルトで無効です。
終了すると ueda@ubuntu:~$ LANG=C man bash 2> /dev/null | grep -A 3 pipefail$
pipefail
If set, the return value of a pipeline is the value of the last (rightmost)
command to exit with a non-zero status, or zero if all commands in the pipeline
exit successfully. This option is disabled by default.
しっかし、これ読んでも一回で正しい意味を読み取れるかどうか自信はありませぬ・・・。
もうちょい補足
見落としに気づいたのは、やっぱりbashの場合、PIPESTATUSが実装されているんだからスクリプトを止める方があるんじゃないかということで、校了後に不安になっていろいろ調べているうちに上記カンニング先で「あっ!」となりました。
「-eだと止まらないことがあるので自分で後始末は実装しましょう」みたいな文脈で-eを説明したのですが、pipefailがあるのでこれは知見の足らん説明となります。
trapと組み合わると、後始末ができてしまいます・・・。
uedambp:~ ueda$ cat pipefail_error.bash
#!/bin/bash -e
set -o pipefail
error () {
echo "ERROR"
#うまくエラーをトラップできればhogeが消える###
rm hoge
}
#中間ファイルを作る###
touch hoge
trap error ERR
false | true
###これ以後は実行されない###
echo do not stop
やってみましょう。
uedambp:~ ueda$ ./pipefail_error.bash
ERROR
###ファイルが消えている###
uedambp:~ ueda$ ls hoge
gls: cannot access hoge: No such file or directory
ああああアホでした。自分で気がついてよかった。
ということで、本書のシェルスクリプトが少し冗長ということが判明しましたが、シェルスクリプトよりワンライナーの方が圧倒的に多いのと、大半のスクリプトは書捨てなので、これを念頭に読んでいただければ大丈夫かと思います。
以上。最後に宣伝。すんません・・・。
寝る。