私はしばらく前に出くわしset -e
、私はそれが大好きだと認めます。さて、しばらくして、bash スクリプトを書くために戻ってきました。
私の質問は、いつ使用するかset -e
、いつ使用しないか (たとえば、小規模/大規模なスクリプトなど)のベスト プラクティスがあるかどうか、またはcmd || exit 1
エラーを追跡するようなパターンを使用する必要があるかどうかです。
はい、常に使用する必要があります。Visual Basic は、"On Error Resume Next" ステートメントがあることもあり、実際のプログラミング言語ではないと常にからかわれます。それでも、それはシェルのデフォルトです! set -e
デフォルトである必要がありました。災害の可能性が高すぎます。
コマンドが失敗しても問題ない場所では、|| true
またはその短縮形||:
を使用できます。
grep Warning build.log ||:
実際には、さらに一歩進んで、
set -eu
set -o pipefail
すべてのbash
スクリプトの先頭に。
-u
などの存在しない環境変数を参照するとエラーになりますが、その代償として、 、 などを参照する前に${HSOTNAME}
チェックを行う必要があります。${#}
${1}
${2}
pipefail
misspeled-command | sed -e 's/^WARNING: //'
エラーを発生させるようなものを作ります。
スクリプト コードが必要に応じて慎重かつ適切にエラーをチェックし、適切な方法でそれらを処理する場合、おそらくset -e
.
一方、スクリプトが次々に実行されるコマンドの単純な順次リストであり、それらのいずれかが失敗した場合にスクリプトを終了する場合set -e
は、一番上に固執することがまさにあなたがやりたいことです.スクリプトをシンプルで整然とした状態に保ちます。これの完璧な例は、一連のソースをコンパイルするスクリプトを作成していて、エラーのある最初のファイルに遭遇した後にコンパイルを停止したい場合です。
より複雑なスクリプトでは、これらのメソッドを組み合わせることができます。これは、 を使用set +e
してその効果を再びオフにし、明示的なエラー チェックに戻ることができるためです。
テストされていないコマンドが失敗した場合にシェルset -e
を終了させるはずですが、コードが独自のエラー処理を行っている場合は、コマンドがゼロ以外を返すという奇妙なケースが簡単に発生する可能性があるため、再度オフにすることをお勧めします。予期しない終了ステータスや、テストでキャッチできないような場合や、スクリプトの突然の致命的な終了によって何かが悪い状態になる可能性があります。そのため、使用しないでください。または、短時間使用した後もオンのままにしておく必要があります。set -e
また、シェルが終了する前に実行されるため、 が有効trap ERR
なときにエラー条件で何かを実行するエラー ハンドラを定義できることにも注意してください。set -e
大好き! ?
私自身は、次.bashrc
のようなラインを使用して、ワイドを好みます。
trap '/usr/games/fortune /usr/share/games/fortunes/bofh-excuses' ERR
(debian の場合: apt-get install fortunes-bofh-excuses
:-)
しかし、それは私の好みにすぎません;-)
もっと真剣に
lastErr() {
local RC=$?
history 1 |
sed '
s/^ *[0-9]\+ *\(\(["'\'']\)\([^\2]*\)\2\|\([^"'\'' ]*\)\) */cmd: \"\3\4\", args: \"/;
s/$/", rc: '"$RC/"
}
trap "lastErr" ERR
Gna
bash: Gna : command not found
cmd: "Gna", args: "", rc: 127
Gna gna
cmd: "Gna", args: "gna", rc: 127
"Gna gna" foo
cmd: "Gna gna", args: "foo", rc: 127
そこから、次のことができます。
trap "lastErr >>/tmp/myerrors" ERR
"Gna gna" foo
cat /tmp/myerrors
cmd: "Gna gna", args: "foo", rc: 1
またはより良い:
lastErr() {
local RC=$?
history 1 |
sed '
s/^ *[0-9]\+ *\(\(["'\'']\)\([^\2]*\)\2\|\([^"'\'' ]*\)\) */cmd: \"\3\4\", args: \"/;
s/$/", rc: '"$RC/
s/^/$(date +"%a %d %b %T ")/"
}
"Gna gna" foo
cat /tmp/myerrors
cmd: "Gna gna", args: "foo", rc: 1
Tue 20 Nov 18:29:18 cmd: "Gna gna", args: "foo", rc: 127
...などの他の情報を追加することもでき$$, $PPID, $PWD
ます..
このオプションがオンの場合、単純なコマンドがシェル エラーの結果にリストされている理由のいずれかで失敗するか、終了ステータス値 >0 を返し、while、until、または if キーワードに続く複合リストの一部ではない場合、およびAND または OR リストの一部ではなく、! が先行するパイプラインでもありません。予約語の場合、シェルはすぐに終了します。