複数の論理演算子、((A || B)&& C)、および「予期しないトークンの近くの構文エラー」


24

私はBash 3で作業しており、条件式を作成しようとしています。C / C ++では、まったく単純です((A || B) && C)。Bashではそうではありませんでした(Gitの作成者は、他の作業に移る前にこのコードを提供したに違いないと思います)。

これは動作しません。<0 or 1>は文字列リテラルではないことに注意してください。0または1を意味します(通常はから来ますgrep -i)。

A=<0 or 1>
B=<0 or 1>
C=<0 or 1>
if [ [ "$A" -eq "0" ] || [ "$B" -ne "0" ] ] && [ "$C" -eqe "0" ]; then ... fi

結果:

line 322: syntax error near unexpected token `[['

次に試しました:

A=<0 or 1>
B=<0 or 1>
C=<0 or 1>
if [ ([ "$A" -eq "0" ]) || ([ "$B" -ne "0" ]) ] && [ "$C" -eq "0" ]; then ... fi

結果は次のとおりです。

line 322: syntax error near unexpected token `[['

問題の一部は、検索結果が単純な例であり、複合条件付きのより複雑な例ではないことです。

((A || B) && C)Bashでシンプルを実行するにはどうすればよいですか?


展開して、複数のブロックで同じコマンドを繰り返す準備ができました。

A=<0 or 1>
B=<0 or 1>
C=<0 or 1>

if [ "$A" -eq "0" ] && [ "$C" -eq "0" ]; then
    ...
elif [ "$B" -ne "0" ] && [ "$C" -eq "0" ]; then
    ... 
fi

回答:


42

bashの構文は、たとえCに触発されたとしても、Cのようなものではありません。Cコードを書いてそれが機能すると期待することはできません。

シェルの主なポイントは、コマンドを実行することです。オープンブラケットコマンド[は、単一のテストを実行するコマンドです¹。test(最後の閉じ括弧なしで)と書くこともできます。||そして&&、オペレータは、彼らが結合する、シェル演算子であるコマンドは、テストしていません。

だから書くとき

[ [ "$A" -eq "0" ] || [ "$B" -ne "0" ] ] && [ "$C" -eq "0" ]

それは次のように解析されます

[ [ "$A" -eq "0" ] ||
[ "$B" -ne "0" ] ] &&
[ "$C" -eq "0" ]

と同じです

test [ "$A" -eq "0" ||
test "$B" -ne "0" ] &&
test "$C" -eq "0"

不均衡な括弧に注意してください?ええ、それは良くありません。括弧を使用した試みにも同じ問題があります:誤った括弧。

コマンドをグループ化する構文は中括弧です。中括弧を解析する方法では、中括弧の前に完全なコマンドが必要なので、中括弧内のコマンドを改行またはセミコロンで終了する必要があります。

if { [ "$A" -eq "0" ] || [ "$B" -ne "0" ]; } && [ "$C" -eq "0" ]; then 

二重括弧を使用する別の方法があります。シングルブラケットとは異なり、ダブルブラケットは特別なシェル構文です。それらは条件式を区切ります。二重括弧の中に、あなたは次のように括弧と演算子を使用することができます&&し、||。二重括弧はシェル構文であるため、シェルはこれらの演算子が括弧内にある場合、通常のシェルコマンド構文の一部ではなく、条件式構文の一部であることを認識しています。

if [[ ($A -eq 0 || $B -ne 0) && $C -eq 0 ]]; then 

すべてのテストが数値である場合、さらに別の方法があります。算術式は、非常にCに似た構文で整数計算を実行します。

if (((A == 0 || B != 0) && C == 0)); then 

私のbashブラケット入門書が役に立つかもしれません。

[プレーンshで使用できます。[[また((、bash(およびkshとzsh)に固有です。

¹ また、複数のテストとブール演算子を組み合わせることができますが、これは使用するのが面倒であり、微妙な落とし穴があるため、説明しません。


おかげでジャイルズ。これは、Bash 2からBash 4に適用されますか?私は何か穏やかに可搬性が必要ですが、Kusalanandaは私がされたいくつか言及していないことは、ポータブルで(それは私がやっているものを意味するものではないことはありませんポータブル?)。ここで、軽度はBash 2からBash 4を意味します

@jww [[ … ]]はbash 2.02で追加されました。((…))bash 2.0で追加されました。
ジル 'SO-悪であるのをやめる'

@Giles-ありがとう。Bash 2はおそらくほとんどの人にとって笑えるでしょう。これは、当社のガバナンスと、古いプラットフォームを放棄したくないためです。Bash 2とGCC 3は、Fedora 1のテストで表示されます。古いプラットフォームを随時公開しますが、それには理由があります。Apple、Microsoft、Mozillaなどの放棄ソフトウェアのポリシーには加入していません。

@jwwことの優先順位を理解してください||&&から変更[する[[((。等しい優先度[(使用括弧は評価の順序を制御するために)、しかし、より高い優先順位&&有し[[且つ((より||(Cのように)。

6

使用[[

if [[ ( "$A" -eq "0" || "$B" -ne "0" ) && "$C" -eq "0" ]]; then ...

ご希望の[場合、次のように機能します:

if [ \( "$A" -eq "0" -o "$B" -ne "0" \) -a "$C" -eq "0" ]; then ...

3

-oネストされた||の代わりに演算子を使用します。また-a、他のステートメントで必要に応じて&&を置き換えるために利用することもできます。

   EXPRESSION1 -a EXPRESSION2
          both EXPRESSION1 and EXPRESSION2 are true

   EXPRESSION1 -o EXPRESSION2
          either EXPRESSION1 or EXPRESSION2 is true


if [  "$A" -eq "0" -o "$B" -ne "0"  ] && [ "$C" -eq "0" ]; then echo success;fi

ありがとう。とに出くわしましたが-a-o試しませんでした。Stack Overflowの誰かがそれを避けるように言った。スクリプトはそれらを使用すると読みにくくなるため、私はそれらにほとんど同意しました。

...しかし、よりポータブル。
クサラナナンダ

@Kusalananda-移植性についてのヘッズアップをありがとう。このスクリプトは、Bash 2〜Bash 4がインストールされたシステムで実行する必要があります。[[ ( "$A" -eq "0" || "$B" -ne "0" ) && "$C" -eq "0" ]]問題はありますか?

あなたbashが理解して[[ ... ]]いるシェルや他のシェルを保持している限り問題はありません。
クサラナナンダ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.