次のスクリプトには構文エラーまたはいくつかのエラーがあります。
#!/usr/bin/env bash
set -euo pipefail
if [ ! -f /custom.log]; then
echo "test"
fi
abcxyz
スクリプトが出力で失敗します。
./test.sh: line 4: [: missing `]'
./test.sh: line 7: abcxyz: command not found
このスクリプトを修正する方法には興味がありませんが、このエラーが発生した場合にスクリプトが継続しないようにするにはどうすればよいですか?私はset -e
この行動が実施されることを期待したでしょう。
答え1
set -e
if
//設定の条件付き部分、aの左側、または関数内、サブシェル、ソースファイル、これらの条件で呼び出されるedコードなど、条件として使用されたコマンドが失敗した場合は実行されません。while
until
||
&&
eval
これが実際にそうであれば:
if [ ! -f /custom.log ]; then
/custom.log
通常のファイルの場合、スクリプトは終了し、[
ゼロ以外の終了状態で終了します。
テスト条件が満たされず、構文エラーがある場合(ただし、すべての構文エラーではない、例えばinではない)、シェルの組み込み[
コマンド(bash
および他のほとんどの実装)は状態で終了します。1
2
[ -v 'a[+]' ]
POSIXでは、エラーが発生した場合に備えて終了状態が1より大きくなければなりません。。
したがって、コマンドが 1 より大きいコードで終了した場合は、条件付きであるかどうかにかかわらずスクリプトを終了することを選択できます。たとえば、次のようになります。
shopt -s extdebug # make sure the DEBUG trap propagates to subshells
trap '(($?>1 && (ret=$?))) && exit "$ret"' DEBUG
[ -f / ] || echo / not a regular file # OK
[ -f /] || echo was a syntax error # causes an exit, not output
echo not reached
トラップはシャットダウンをトリガするのと同じ条件でのみ実行されるため、ERR
トラップは使用できません。ERR
set -e
さて、その意味を知ってください。たとえば、結果は次のようになります。
if grep -qs pattern /file; then
echo pattern was found in /file
fi
/file
存在しない、または読み取れない場合は終了します。grep
この場合、戻り状態は 2 です。たとえ使用されても、-s
明らかにこれらのケースを無視する意図です。
したがって、条件に使用するコマンドが1より大きい状態で終了できる条件を知っておく必要があります。これらの問題を解決するには、次のものが必要です。
if sh -c 'grep -sq pattern / file || exit 1'; then...
制限することができます終了ステータスが1より大きい場合は終了します。[
orコマンドに接続しますtest
。たとえば、次のようになります。
unset -v previous_BASH_COMMAND
trap '
case $previous_BASH_COMMAND in
("[ "* | "test "*) (($?>1 && (ret=$?))) && exit "$ret"
esac
previous_BASH_COMMAND=$BASH_COMMAND' DEBUG
これにはいくつかの制限があります。存在する
echo x
([ -f/]; echo y)
これによりサブシェルは終了しますが、親シェルは$previous_BASH_COMMAND
そこに設定されていないため終了しません。そして:
[ -f / ] && echo a regular file
(grep -qs foo /file && echo foo in /file)
echo here
willは2でwasなのでecho here
、実行中にシェルが終了します。$?
$previous_BASH_COMMAND
[ -f / ]
とにかく、
[ -f /] | cat
export var="$([ -f /])"
終了状態が親シェルプロセスに伝播されないため、終了状態を検出できません(pipefail
最初の場合のオプションを除く)。
バグは開発時(スクリプトの作成とテスト時に)簡単に検出されるため、実行時にこの(脆弱な)検出を追加する価値があるかどうかはわかりません。