回答:
多くのコンピューター言語では、同じ優先順位を持つ演算子は左結合です。つまり、グループ化構造がない場合、左端の操作が最初に実行されます。Bashはこのルールの例外ではありません。
Bashでは同じ優先順位&&
を||
持っているため、これは重要です。
あなたの例で起こることは、左端の操作(||
)が最初に実行されることです:
true || echo aaa
以来true
、明らかに事実である、||
オペレータ短絡や文全体を評価する必要なしに、真とみなされecho aaa
ますが、期待通り。これで、右端の操作を行うことができます。
(...) && echo bbb
最初の操作はtrueと評価された(つまり、終了ステータスが0だった)ため、実行しているように見えます
true && echo bbb
ので、&&
短絡しないので、bbb
エコーが表示されます。
あなたは同じ振る舞いを得るでしょう
false && echo aaa || echo bbb
コメントに基づくメモ
[[...]]
((...))
-o
-a
test
[
&&
-a
||
-o
と思われるCにし、C-ような言語&&
よりも高い優先順位がある||
あなたは、元の構文は次のように動作するように期待する理由はおそらくであるが
true || (echo aaa && echo bbb).
ただし、これはBashの場合ではなく、両方の演算子の優先順位が同じであるため、Bashは左結合規則を使用して式を解析します。これを提起してくれたケビンのコメントに感謝します。
3つの式すべてが評価される場合もあります。最初のコマンドがゼロ以外の終了ステータスを返した場合、||
ショートすることはなく、2番目のコマンドを実行し続けます。2番目のコマンドがゼロの終了ステータスで戻った場合、&&
同様に短絡することはなく、3番目のコマンドが実行されます。これを提起してくれたIgnacio Vazquez-Abramsのコメントに感謝します。
&&
は、より優先順位が高い||
ため、OPの予期される動作が発生します。そのような言語に慣れている不注意なユーザーは、bashで同じ優先順位を持っていることに気付かない場合があるため、bashで同じ優先順位を持っていることをより明確に指摘する価値があります。
条件に応じて複数のことをしたい場合は、それらをグループ化します。
true || { echo aaa && echo bbb; }
それは何も印刷しませんが、
true && { echo aaa && echo bbb; }
両方の文字列を出力します。
これが起こる理由は、ジョセフが考えているよりもずっと簡単です。バッシュはで何をするかを覚えておいてください||
と&&
。それはすべて、前のコマンドの戻りステータスに関するものです。生のコマンドを文字通り見る方法は次のとおりです。
( true || echo aaa ) && echo bbb
最初のコマンド(true || echo aaa
)はで終了してい0
ます。
$ true || echo aaa; echo $?
0
$ true && echo aaa; echo $?
aaa
0
$ false && echo aaa; echo $?
1
$ false || echo aaa; echo $?
aaa
0
(true || echo aaa) && echo bbb
はまさに私が作っているものであることに注意してください。
;
最後のセミカラムに注意してください。これがないと機能しません!
echo bbb;
最初の例)の後に末尾のセミコロンがなかったため、これで問題が発生していました。私がそれを見逃していたことがわかったら、この答えはまさに私が探していたものでした。+1は、私が望んでいたことを達成する方法を理解するのを助けてくれました!
演算子はありませんされたif-then-elseの正確なインライン交換。ただし、慎重に使用すれば、ほぼ同じことを達成できます。&&
||
単一のテストは簡単で明確です...
[[ A == A ]] && echo TRUE # TRUE
[[ A == B ]] && echo TRUE #
[[ A == A ]] || echo FALSE #
[[ A == B ]] || echo FALSE # FALSE
ただし、複数のテストを追加しようとすると、予期しない結果が生じる可能性があります...
[[ A == A ]] && echo TRUE || echo FALSE # TRUE (as expected)
[[ A == B ]] && echo TRUE || echo FALSE # FALSE (as expected)
[[ A == A ]] || echo FALSE && echo TRUE # TRUE (as expected)
[[ A == B ]] || echo FALSE && echo TRUE # FALSE TRUE (huh?)
なぜFALSE と TRUEの両方がエコーされるのですか?
何ここで起こっていることは、我々はそれを実現していませんでしたということである&&
と||
の条件付きテスト括弧内の異なる動作をオペレータオーバーロードされ[[ ]]
、彼らは我々がここにあるANDとOR(条件実行)リストで行うよりもを。
bashのマンページから(編集済み)...
リスト
リストは、演算子;、&、&&、または│|のいずれかで区切られた1つ以上のパイプラインのシーケンスであり、オプションで;、&、または。のいずれかで終了します。これらのリスト演算子のうち、&&と││の優先順位は等しく、その後に;が続きます。および&、同等の優先順位があります。
コマンドを区切るために、1つ以上の改行のシーケンスがセミコロンではなくリストに表示される場合があります。
コマンドが制御演算子&によって終了された場合、シェルはサブシェルのバックグラウンドでコマンドを実行します。シェルはコマンドが終了するまで待機せず、戻りステータスは0です。順次実行されます。シェルは各コマンドが順番に終了するのを待ちます。戻りステータスは、最後に実行されたコマンドの終了ステータスです。
ANDおよびORリストは、それぞれ&&および││制御演算子で区切られた1つ以上のパイプラインのシーケンスです。ANDおよびORリストは左結合で実行されます。
ANDリストの形式は...です
command1 && command2
。command2は、command1が終了ステータス0を返す場合にのみ実行されます。ORリストの形式は... ...
command1 ││ command2
command2が実行されるのは、command1がゼロ以外の終了ステータスを返す場合のみです。ANDおよびORリストの戻りステータスは、リストで最後に実行されたコマンドの終了ステータスです。
最後の例に戻ります...
[[ A == B ]] || echo FALSE && echo TRUE
[[ A == B ]] is false
|| Does NOT mean OR! It means...
'execute next command if last command return code(rc) was false'
echo FALSE The 'echo' command rc is always true
(i.e. it successfully echoed the word "FALSE")
&& Execute next command if last command rc was true
echo TRUE Since the 'echo FALSE' rc was true, then echo "TRUE"
はい。それが正しい場合、最後から2番目の例が何もエコーしないのはなぜですか?
[[ A == A ]] || echo FALSE && echo TRUE
[[ A == A ]] is true
|| execute next command if last command rc was false.
echo FALSE Since last rc was true, shouldn't it have stopped before this?
Nope. Instead, it skips the 'echo FALSE', does not even try to
execute it, and continues looking for a `&&` clause.
&& ... which it finds here
echo TRUE ... so, since `[[ A == A ]]` is true, then it echos "TRUE"
複数のコマンドを使用し&&
たり||
、コマンドリストで使用したりすると、論理エラーのリスクが非常に高くなります。
推奨事項
単一&&
または||
コマンドリストは期待どおりに機能するため、非常に安全です。else節を必要としない状況の場合、次のようなことがわかりやすくなります(最後の2つのコマンドをグループ化するには中括弧が必要です)...
[[ $1 == --help ]] && { echo "$HELP"; exit; }
複数の&&
and ||
演算子は、最後を除く各コマンドがテスト(つまり[[ ]]
、かっこ内)である場合、通常、最後の演算子を除くすべてが期待どおりに動作するため安全です。最後の演算子は、then
or else
句のように機能します。
私もこれに困惑しましたが、Bashがあなたの声明を読む方法について考えています(左から右に記号を読むように):
true
。コマンドの最後に到達したら、これを評価する必要があります。この時点で、引数があるかどうかはわかりません。コマンドを実行バッファに保存します。||
。前のコマンドは完了しましたので、評価してください。コマンド(バッファ)が実行されています:true
。評価の結果:0(つまり成功)。結果0を「最後の評価」レジスタに保存します。次に、シンボル||
自体を検討します。これは、最後の評価がゼロ以外の結果に依存します。「最後の評価」レジスタをチェックし、0を見つけました。0は非ゼロではないため、次のコマンドを評価する必要はありません。echo
。次のコマンドを評価する必要がないため、このシンボルを無視できます。aaa
。これはコマンドecho
(3)の引数ですが、echo
(3)を評価する必要がないため、無視できます。&&
。これは、最後の評価の結果がゼロに依存します。「最後の評価」レジスタをチェックし、0を見つけました。0はゼロなので、次のコマンドを評価する必要があります。echo
。次のコマンドを評価する必要があったため、コマンドの最後に到達したら、このコマンドを評価する必要があります。コマンドを実行バッファに保存します。bbb
。これはコマンドecho
(6)の引数です。以来echo
評価する必要がなかった、追加bbb
実行バッファへ。echo bbb
。評価の結果:0(つまり成功)。結果0を「最後の評価」レジスタに保存します。そしてもちろん、最後のステップbbb
はコンソールにエコーされます。
&&
と||
asの演算子cmd1 && cmd2 || cmd3
は同じ優先順位を持ちますが、&&
in((...))
とin[[...]]
は優先順位が||
(((a || b && c))
is((a || (b && c)))
)です。同じことがのために行く-a
/-o
中test
/[
及びfind
及び&
/|
中expr
。