[[expr1 ||の違い expr2]]および[[expr1]] || [[expr2]]


6

2つの条件式expr1andを考えます。expr2たとえば$i -eq $j、と$k -eq $lです。これbashはさまざまな方法で書くことができます。ここに2つの可能性があります

[[ expr1 || expr2 ]]

[[ expr1 ]] || [[ expr2 ]]

ここでは2番目の方が好ましいという推奨事項を見たことがあると思いますが、これを裏付ける証拠は見つかりません。

以下は、違いがないことを示すサンプルスクリプトです。

for i in 0 1
do
  for j in 0 1
  do
    for k in 0 1
    do
      for l in 0 1
      do
        if [[ $i -eq $j || $k -eq $l ]]; then printf "1-yes\t"; else printf "1-no\t"; fi
        if [[ $i -eq $j ]] || [[ $k -eq $l ]]; then printf "2-yes\n"; else printf "2-no\n"; fi
      done
    done
  done
done

両方の条件構文が同じ結果を生成することを示す出力:

1-yes   2-yes
1-yes   2-yes
1-yes   2-yes
1-yes   2-yes
1-yes   2-yes
1-no    2-no
1-no    2-no
1-yes   2-yes
1-yes   2-yes
1-no    2-no
1-no    2-no
1-yes   2-yes
1-yes   2-yes
1-yes   2-yes
1-yes   2-yes
1-yes   2-yes

ある構成を他の構成よりも使用する利点はありますか?

ボーナスポイントについては、同じ質問ですが、||およびを使用して複数の条件に一般化します&&。たとえば、[[ expr1 && expr2 || expr3 ]]


なぜこのタイプの推奨がしばしばwrtで与えられるかに関して。[またはtest(ではない [[OBPOSIX仕様でtestタグ(「陳腐化した」定義にリンクされている)を検索します。ではtest、テストコマンドやテスト対象の文字列にとって意味のある構文であるかどう(かを判断できない病理学的なケースがいくつか)あります。そのため、陳腐化マーカーを無視してその構文を使用する人は、実際にはそうでなければ-時代遅れの"x$foo"慣習; と[[、それは問題ではありません。
Charles Duffy

回答:


7

あなたが見た推奨は、POSIX shおよび/またはtestコマンドとしても機能する[コマンドに対する[[ものであり、kshに表示された構成(チップのStéphaneChazelasに感謝)ではなく、たとえばbash、zshおよびその他のいくつかで使用されていると思いますシェル。

ほとんどの言語では、Cのように、句がすでに真または偽であることが知られているとき、操作に応じて、残りの部分を評価する必要はありません:trueの場合ではないの後に論理的そうでない場合はfalse論理た後、それに続く、もちろん、これにより、たとえば、ポインタがNULLのときに停止し、次の句でそれを逆参照しないようにすることができます。

しかし、sh[ expr1 -o expr2 ]構造(bashの実装を含む)はこれを行いません。expr1のみを評価したい場合は、常に両側を評価します。これは、testコマンド実装との互換性のために行われた可能性があります。一方、SHの||&&、それは結果を変えない場合は評価されません:いつもの原則に従ってください。

したがって、注意すべき違いは次のとおりです。

: > /tmp/effect #clear effect
if [ 1 -eq 1 -o $(echo 1; echo or-was-evaluated > /tmp/effect) -eq 1 ]; then
    echo true;
fi
cat /tmp/effect

これにより、

true
or-was-evaluated

上記では、それぞれ[がシェルに組み込まれる前に使用され/usr/bin/[ていたtestコマンドのエイリアスであるに置き換えることができ[ました。

一方、次の2つの構成は:

: > /tmp/effect #clear effect
if [ 1 -eq 1 ] || [ $(echo 1; echo or-was-evaluated > /tmp/effect) -eq 1 ]; then
    echo true;
fi
cat /tmp/effect

または

: > /tmp/effect #clear effect
if [[ 1 -eq 1 || $(echo 1; echo or-was-evaluated > /tmp/effect) -eq 1 ]]; then
    echo true;
fi
cat /tmp/effect

のみを生成しtrueeffect空のままにします。||正しく動作し、[[この問題も修正されました。


更新:

@StéphaneChazelasがコメントしたように、最初の質問に関連するいくつかの違いを見逃しました。ここで最も重要なもの(少なくとも私にとって)をここに置きます:オペレーターの優先順位。

シェルは優先順位を考慮しませんが、

if true || true && false; then
    echo true
else
    echo false
fi

利回り(優先順位がないため、最初true || trueに評価され、次に&& false):

false

内部の演算子に優先しています。[[ ]]&&||

if [[ 1 -eq 1 || 1 -eq 1 && 1 -eq 0 ]]; then
    echo true
else
    echo false
fi

利回り(1 -eq 1 && 1 -eq 0グループ化されているため、の2番目のメンバーであるため||):

true

少なくともkshbashzshについては

したがって[[ ]]、両方[ ]と直接のシェル論理演算子の動作が改善されました。


1
[ x -o y ]両方を評価する必要はありません。GNU testやdo の[組み込みでbashは、stat()を試そうstrace zsh -c '[ x -o -f /x ]'[はしません/x。と同じmkshです。しかし、それは事実だ-oとは-aひどく壊れている、信頼して使用することができず、POSIXによって廃止されました。
ステファンChazelas

1
1つの違いは、その内部で[[...]]&&より高い優先順位を有し||、それらが同じ優先順位を有する外部ながら、。比較ksh -c '[[ x || x && "" ]]'sh -c 'true || true && false'
ステファンChazelas

1
標準の[/ testユーティリティには==演算子がないことに注意してください。等価演算子は次のとおりです=(kshの内部では[[...]]=/ ==は等価演算子ではなく、パターンマッチング演算子です)。
ステファンChazelas

1
それは逆です。内部(または)&&よりも優先され||ますが、およびシェル演算子よりも優先されます。is while is (演算子は左から右に優先度なしで評価されます)。どのように似たよりも優先されます(ある)が、そして同じ優先順位を持っています。[[...]]((...))&&||[[ x || y && z ]]x || (y && z)x || y && z(x || y) && z*+1 + 2 * 31 + (2 * 3)+-
ステファンChazelas

1
場合は&&優先順位以上を持って||、それがあるべきtrue || (true && false)代わりに、(true || true) && false
Prvt_Yadav
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.