web-dev-qa-db-ja.com

構文エラー時にスクリプトの実行をbashに中止させる方法は?

安全のために、構文エラーが発生した場合、bashはスクリプトの実行を中止します。

驚いたことに、私はこれを達成できません。 ( set -e では不十分です。)例:

#!/bin/bash

# Do exit on any error:
set -e

readonly a=(1 2)

# A syntax error is here:

if (( "${a[#]}" == 2 )); then
    echo ok
else
    echo not ok
fi

echo status $?

echo 'Bad: has not aborted execution on syntax error!'

結果(bash-3.2.39またはbash-3.2.51):

$ ./sh-on-syntax-err
./sh-on-syntax-err: line 10: #: syntax error: operand expected (error token is "#")
status 1
Bad: has not aborted execution on syntax error!
$ 

構文エラーをキャッチするためにすべてのステートメントの後に$?をチェックすることはできません。

(私は賢明なプログラミング言語からそのような安全な動作を期待していました...多分これはバグ/開発者への願いとして報告する必要があります)

その他の実験

ifは違いがありません。

ifを削除しています:

#!/bin/bash

set -e # exit on any error
readonly a=(1 2)
# A syntax error is here:
(( "${a[#]}" == 2 ))
echo status $?
echo 'Bad: has not aborted execution on syntax error!'

結果:

$ ./sh-on-syntax-err 
./sh-on-syntax-err: line 6: #: syntax error: operand expected (error token is "#")
status 1
Bad: has not aborted execution on syntax error!
$ 

おそらく、それは http://mywiki.wooledge.org/BashFAQ/105 の演習2に関連しており、(( ))と関係があります。しかし、構文エラーを続けて実行するのはまだ理不尽です。

いいえ、(( ))は違いません!

算術テストがなくても動作が悪い!単純で基本的なスクリプト:

#!/bin/bash

set -e # exit on any error
readonly a=(1 2)
# A syntax error is here:
echo "${a[#]}"
echo status $?
echo 'Bad: has not aborted execution on syntax error!'

結果:

$ ./sh-on-syntax-err 
./sh-on-syntax-err: line 6: #: syntax error: operand expected (error token is "#")
status 1
Bad: has not aborted execution on syntax error!
$ 

全体を関数にラップするのがトリックを行うようです:

#!/bin/bash -e

main () {
readonly a=(1 2)
    # A syntax error is here:
    if (( "${a[#]}" == 2 )); then
        echo ok
    else
        echo not ok
    fi
    echo status $?
    echo 'Bad: has not aborted execution on syntax error!'
}

main "$@"

結果:

$ ./sh-on-syntax-err 
$ ./sh-on-syntax-err line 6: #: syntax error: operand expected (error token is "#")
$ 

理由はわかりませんが、誰か他の人が説明できますか?

9
ahilsend

set -eの真の意味について誤解している可能性があります。 help setの出力を注意深く読むと、次のことがわかります。

-e  Exit immediately if a command exits with a non-zero status.

つまり、-ecommandsの終了ステータスがゼロ以外であることであり、スクリプトの構文エラーではありません。

一般に、set -eを使用することは悪い習慣と見なされます。すべてのエラー(つまり、コマンドからのゼロ以外のすべての戻り)は、スクリプトによって適切に処理される必要があるためです(堅牢なスクリプトと考えてください。スペースを含むファイル名、またはハイフンで始まるファイル名を入力してください)。

構文エラーの種類によっては、スクリプトがまったく実行されないこともあります。私はbashについて十分な知識がなく、正確にどのクラスの構文エラー(分類できる場合のみ)がスクリプトの即時中止につながるかを教えてくれません。たぶんいくつかのバッシュの教祖が参加し、すべてを明確にするでしょう。

set -eステートメントを明確にしたいと思います!

あなたの願いについて:

私は賢明なプログラミング言語からそのような安全な動作を期待していました...おそらくこれはバグ/開発者への要望として報告する必要があります

答えは間違いなくno!あなたが観察したこと(set -e期待どおりに応答しない)は実際に非常によく文書化されているためです。

6
gniourf_gniourf

あなたは次のようなものを置くことによってスクリプト自体をチェックさせることができます

bash -n "$0"

スクリプトの先頭近く-set -eの後、重要なコードの前。

これはあまり堅牢ではないと感じなければなりませんが、それがあなたのために働くなら、おそらくそれは許容できます。

4
tripleee

まず、bashの(( ))は算術計算として使用されます。if...では使用せず、[]を使用します。

次に、${a[#]}は奇妙で、エラーが発生するのはそのためです...#には配列の意味がありません

これで何をしたいのかわかりませんが、フィールドの数を知りたいので、代わりに${#a[*]}が必要です

最後に、整数を比較するときは、-eqよりも==をお勧めします(文字列に使用)。 ==も機能しますが、-eqをお勧めします。

あなたが望んでいるのは:

if [ ${#a[*]} -eq 2 ]; then 
0
higuita