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

私はBash3を使用していますが、条件付きを形成します。 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=<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 

回答

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)に固有です。

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

コメント

  • Gilesに感謝します。これはBash2からBash4にも当てはまりますか?少し移植性が必要ですが、Kusalanandaは、私がしなかったいくつかのことは移植可能であると述べました(これは、私がしていることはポータブルではありませんか?)ここで、穏やかにはBash2からBash4を意味します。
  • @jww [[ … ]]が追加されました((…))がbash2.0に追加されました。
  • @ Giles-ありがとう。Bash2はおそらくほとんどの人にとって笑えるものです。これは、私たちのガバナンスと不本意によるものです。古いプラットフォームを放棄する。Bash2とGCC3がFedora1のテストに表示されます。古いプラットフォームをときどき手放しますが、それには理由があります。'アバンダンウェアのApple、Microsoft、Mozillaなどのポリシーに同意します。
  • @jww ||[から[[および((に変更します。 [優先順位と同じです(括弧を使用して評価の順序を制御します)が、& &は[[((

(Cのように)。

  • @Rolandいいえ、[[ … ]]または$((…))はグループ化のためだけのものです。
  • 回答

    [[を使用:

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

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

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

    コメント

    • ありがとう、スティーブン。私の場合、最初の例をこのように使用しました… regex = ' ^ [0-9] + $ ' length = $ {#datearg} if! [[$ datearg =〜$ regex & & $ length -eq 8]];次に、エコー"エラー:8の長さの数ではありません"; fi

    回答

    代わりに-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に出くわしましたが、実験はしませんでした。 StackOverflowの誰かがそれを避けるように言った。スクリプトはそれらを使用すると読みにくくなるため、私はほとんど同意しました。
    • …しかし、より移植性があります。
    • @ Kusalananda-移植性に関するヘッドアップに感謝します。スクリプトは、Bash2からBash4を搭載したシステムで実行する必要があります。[[ ( "$A" -eq "0" || "$B" -ne "0" ) && "$C" -eq "0" ]]で問題が発生しますか?
    • bashまたは[[ ... ]]を理解するその他のシェル。
    • -aを使用することの欠点は'最初の式が偽の場合は短絡します。したがって、潜在的な致命的な2番目の式の実行を防ぐために短絡に依存している場合は、-aを使用できません。例: pastebin.com/zM77TXW1

    コメントを残す

    メールアドレスが公開されることはありません。 * が付いている欄は必須項目です