なぜbashスクリプトで「&&」を使用しないのですか?

37
2022.01.03

私は2つの条件を持つ単純なifセクションを含むbashスクリプトを書いています:

   if [[ -n $VAR_A ]] && [[ -n $VAR_B ]]; then
    echo >&2 "error: cannot use MODE B in MODE A" && exit 1
  fi

シニアエンジニアが私のコードをレビューし、コメントしました:

代わりに、後続の行で2つのコマンドを実行できる場合は、&&の使用を避けてください。

彼はそれ以上説明しなかった。しかし、好奇心から、これが本当かどうか、そして&&の使用を避ける理由は何でしょうか。

回答
27
2022.01.03

レビューコメントは、おそらく&&演算子の2番目の使用法に言及しています。 echoが失敗した場合に終了したくないので、コマンドを別々の行に書き込む方が理にかなっていると思います。

 if [[ -n $VAR_A ]] && [[ -n $VAR_B ]]; then
    echo >&2 "error: cannot use MODE B in MODE A"
    exit 1
fi

ところで、あなたは[[ ... ]]条件内&&を含めることができます。

 if [[ -n $VAR_A && -n $VAR_B ]]; then
23
2022.01.03

これは&&に対する一般的なコメントではありません。あなたが話をしたエンジニアは、echo自体が失敗した(非常にありそうもないが、理論的には可能である)ケースを検討していたと思います。あなたがこれを持っている場合:

 if error; then
    echo foo && exit
fi

その後、何らかの理由でechoコマンドが失敗した場合、 exitは実行されないため、実際にエラーをキャッチすることはありません。それらを分離している場合、 echoが失敗してもexitは実行されます。

 if error; then
    echo foo
    exit 
fi

したがって、エンジニアは、これら2つの特定のステートメントを分離する方が安全であるということは確かに正しいです。ただし、これを&&の使用に対する一般的な指示として解釈しないでください。 &&は、あるコマンドの実行を別のコマンドの正常な実行に依存させたい場合にのみ使用するようにしてください。

たとえば、これは完全に問題ありません。

 command && echo 'command worked!' 
14
2022.01.05

人々はechoが失敗したことに対して良い主張をしました。正確さに関するこの点に加えて、読みやすさを主張することもできます。あなたが書いた

echo >&2 "error: cannot use MODE B in MODE A" && exit 1

それを頭の中で英語に翻訳すると、次のようになります。

以下を標準エラーに出力します:「エラー:モードAでモードBを使用できません」
印刷操作が正常に完了した場合は、コード1で終了します。

これを読んでいる人は、「印刷操作が正常に完了したかどうかをわざわざ指定したのはなぜですか」と尋ねる可能性があります。コード内のより少ないロジックがあるので、この場合には、2行は&&より単純です。推奨される2行の代替案の英語版は次のとおりです。

以下を標準エラーに出力します:「エラー:モードAでモードBを使用できません」
次に、コード1で終了します

それはそれほど複雑ではないので、それを読むのに必要な脳力は少なくなります。 &&が何のためにあるのか疑問に思うことはありません。

10
2022.01.04

簡単に言えば、出口パスで実行されたコード自体がエラーを引き起こさないと想定するべきではありません。これはシェルスクリプトに固有のものではありませんが、一般的には優れたプログラミングアドバイスです。

echo ‘foo’ && exitを使用すると、echo 'foo'が成功した場合にのみ終了します。その失敗の可能性は確かに非常に低いですが、特にそれを正しく行うためのコストが非常に小さい場合は、それを当てにするべきではありません。これは、コード内の他の関数を呼び出す可能性のあるより複雑な出口パスがあり、出口パスがechoのような「最も安全な」ものだけを呼び出すことは明らかではない場合に非常に重要になりますが、「正しい」を使用するのが一般的に良い形式ですすべての場合にコードを記述して、適切に実行する習慣を身に付けます(そして、同僚が何を期待できるかを知っています)。

何らかの理由で、あなたはそれが1行(私はこれはものの場合であってはなりません主張するだろう)である必要があり、場合、正しい構文は、彼らが別の行にあったかのようにパーサが2つのコマンドを治療するための原因echo 'foo' ; exit、です。


余談ですが、条件付きでは、ほとんどの場合、次のいずれかを選択する必要があります。

 if [[ -n $VAR_A && -n $VAR_B ]]; then

これはbash固有ですが、現在持っているものよりも効率的です。または:

 if [ -n "$VAR_A" ] && [ -n "$VAR_B" ]; then

これは、POSIX準拠のシェルで意味的に同等の方法で機能します。

1
2022.01.11

1行に2つのコマンドを書く必要はありません。 ifステートメントに100個のコマンドが含まれている場合、読むのが恐ろしいため、それらを一緒に&&することはできません。エコー障害の可能性に関する他の回答は技術的には正しいものですが、上級開発者の意図は読みやすさに関するものだったと思います。