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


15

安全のために、構文エラーが発生した場合、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!
$ 

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

(賢明なプログラミング言語からこのような安全な動作を期待していました...おそらくこれはバグ/要望としてbash開発者に報告されなければなりません)

より多くの実験

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!
$ 

set -e構文エラーがifステートメントにあるため、十分ではありません。他の場所ではスクリプトを中止する必要があります。
ヨルダン

@jordanm OK、これはなぜ機能しset -eなかったのかの説明になります。しかし、私の質問はまだ理にかなっています。構文エラーで中止することは可能ですか?
imz-イワンザカリヤシェフ

@jordanm「if」を削除。違いはありません(私の質問を更新しました)。
imz-イヴァンザカリヤシェフ

回答:


9

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

#!/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 "#")
$ 

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


2
これで、関数定義が解析および評価され、失敗します。
トリプリー

いい解決策!ところで、この場合もプログラム全体を中止しません。echo 'Bad2: has not aborted the execution after bad main!'最後の例として追加しました。出力は次のとおりです。$ LC_ALL = C ./sh-on-syntax-err ./sh-on-syntax-err:6行目:#:構文エラー:オペランドが必要です(エラートークンは「#」です)Bad2:悪いメインの後に実行を中止していません!$
imz-イワン・ザハリヤシェフ

しかし、単純に行を追加するのではなく、すべてを関数内に配置する必要があります。
imz-イヴァンザカリヤシェフ

@tripleeeはい、関数の解析が失敗したように見えるため、完全ではありませんが、この場合、プログラム全体は実際には中止されません(したがって、おそらくエラー終了の影響ではありません)。
imz-イヴァンザカリヤシェフ

6

あなたはおそらくの本当の意味について誤解しているでしょうset -ehelp setショーの出力を注意深く読むと:

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

したがって-eコマンドの終了ステータスはゼロ以外であり、スクリプトの構文エラーに関するものではありません。

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

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

私はset -e声明を明確にしたいだけです!

あなたの願いについて:

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

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


私はそのような機能の欠如が問題であることを意味しました。私は焦点を当てたくありませんでしたset -e-それは私の目標に少し近づいているので、ここで言及されて使用されています。私の質問はについてset -eではありません。それは、構文エラーで中止させることができない場合のbashの安全性に関するものです。構文エラーで常に中止する方法を探しています。
imz-イヴァンザカリヤシェフ

4

次のようなものを追加することで、スクリプト自体をチェックすることができます

bash -n "$0"

スクリプトの最上部付近- set -e重要なコードの後、ただし前に。

これは非常に堅牢ではないと言う必要がありますが、それがあなたのために機能するのであれば、おそらく受け入れられるでしょう。


優秀な!または、なし set -ebash -n "$0" || exit
ダニエルS

0

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

第二に、これ${a[#]}は奇妙であり、それがエラーを与える理由です... #配列の意味がありません

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

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

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

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

4
それは真実ではない。((キーワードとともにキーワードを使用することは一般的ifです。たとえば、if (( 5 * $b > 53 ))。古い殻を持つ可搬性を目指している場合を除き、[[ある一般的に好ましいオーバー[

2
はい、@ Evanに同意します- [[そして((、「if」などで使用される軽量テストとして特別に設計されました- とは異なり[、それらは条件を評価するためにサブプロセスを生成しません。
imz-イワンザカリヤシェフ

1
[bashビルトインです。古いシェルはそれがそれ自身のプログラムであると期待しています。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.