Bashの単純な論理演算子


256

いくつかの変数があり、次の条件をチェックしたいと思います(言葉で書き出され、その後bashスクリプトでの失敗した試行)。

if varA EQUALS 1 AND ( varB EQUALS "t1" OR varB EQUALS "t2" ) then 

do something

done.

そして、私の失敗した試みで、私は思いつきました:

if (($varA == 1)) && ( (($varB == "t1")) || (($varC == "t2")) ); 
  then
    scale=0.05
  fi

回答:


682

あなたが書いたものは実際にはほとんど機能します(すべての変数が数値であれば機能します)が、それはまったく慣用的な方法ではありません。

  • (…)括弧はサブシェルを示します。それらの中にあるものは、他の多くの言語のような表現ではありません。これはコマンドのリストです(括弧の外と同じです)。これらのコマンドは別のサブプロセスで実行されるため、括弧内で実行されたリダイレクトや割り当てなどは、括弧外では効果がありません。
    • 先頭のドル記号$(…)は、コマンドの置換です:括弧内にコマンドがあり、コマンドからの出力はコマンドラインの一部として使用されます(二重引用符で囲まれていない限り、追加の展開の後、それは別の話です) 。
  • { … }中かっこは、コマンドをグループ化する点ではかっこに似ていますが、グループ化ではなく解析にのみ影響します。プログラムx=2; { x=4; }; echo $xは4をx=2; (x=4); echo $x出力しますが、2を出力します(中括弧は閉じる前にそれらの前後にスペースとセミコロンが必要ですが、括弧はそうではありません。これは構文の癖です)。
  • ((…))二重括弧は、算術命令(整数の計算)を囲みます。構文は、他のプログラミング言語に似ています。この構文は、主に代入と条件式で使用されます。
    • 同じ構文が算術式$((…))で使用され、式の整数値に展開されます。
  • [[ … ]]二重括弧は条件式を囲みます。条件式は、主に上に構築されている事業者などの-n $variable変数が空とあるかどうかをテストするために-e $fileファイルが存在するかどうかをテストします。文字列等価演算子もあります:("$string1" == "$string2"右側がパターンであることに注意してください。たとえば、[[ $foo == a* ]]if $fooawhileで始まる[[ $foo == "a*" ]]場合test $fooが正確にif a*)、否定、結合、分離のための使い慣れた!、演算子、&&および||グループ化のための括弧です。各演算子の周りにはスペースが必要であることに注意してください(例:[[ "$x" == "$y" ]]not [[ "$x"=="$y" ]])、;括弧の内側と外側の両方のようなスペースまたは文字(例:[[ -n $foo ]]not[[-n $foo]])。
  • [ … ]単一の角括弧は、より多くの奇妙な(ただし古くて移植性の高い)条件式の代替形式です。今は何も書かないでください。それらを含むスクリプトを見つけたら、それらについて心配し始めます。

これは、bashでテストを記述する慣用的な方法です。

if [[ $varA == 1 && ($varB == "t1" || $varC == "t2") ]]; then

他のシェルへの移植性が必要な場合は、これがその方法です(個々のテストを囲む追加の引用符とブラケットの個別のセット、および=ksh / bash / zsh ==バリアントではなく従来の演算子の使用に注意してください)。

if [ "$varA" = 1 ] && { [ "$varB" = "t1" ] || [ "$varC" = "t2" ]; }; then

31
素晴らしい投稿、括弧の要約はまさに理想的です。
KomodoDave 2013年

10
==比較を変数(これも=)の割り当てと区別するために使用する方がよい
Will Sheppard

1
ああ、私は混乱を招いて申し訳ありませんが、単一(丸)括弧を意味しました。[[ $varA = 1 && ($varB = "t1" || $varC = "t2") ]]最初の箇条書きで「[かっこ]の内側他の多くの言語のような式ではありません」と明確に述べられていますが、のサブプロセスは開始されませんが、確かにここにあります!これは、経験豊富なbashウィズにはおそらく明らかですが、すぐにはわかりません。二重括弧内の式ではなく、ステートメント内で単一の括弧使用できるため、混乱が生じる可能性がありifます。
ピーター-モニカの復活

2
@protagonist ==は実際にはほど「慣用的」ではありません=。それらは同じ意味を持っています==が、=移植性がある一方でbashとzshでも利用可能なkshバリアントです。を使用することに本当に利点==はなく、プレーンなshでは機能しません。
Gilles「SO-邪悪なことをやめよ」

2
@WillSheppard比較と代入の間には他にも多くの違いがあります。比較は括弧内にあり、代入はそうではありません。比較では、演算子の周りにスペースがありますが、代入にはありません。代入は左側に変数名があり、比較では左側に変数名のように見えるものはほとんどなく、とにかく引用符を付けることができます。必要に応じてで==内部[[ … ]]に書き込むこともできますが、=でも作業できるという利点があります[ … ]。そのため==、まったく使用する習慣をつけないことをお勧めします。
Gilles「SO-邪悪なことをやめよ」

34

とても近い

if [[ $varA -eq 1 ]] && [[ $varB == 't1' || $varC == 't2' ]]; 
  then 
    scale=0.05
  fi

うまくいくはずです。

それを分解する

[[ $varA -eq 1 ]] 

整数比較です。

$varB == 't1'

文字列比較です。それ以外の場合は、比較を正しくグループ化しています。

二重角括弧は、条件式を区切ります。そして、私はこの件に関して次のことを読むのが良いでしょう:"(IBM)Demystify test、[、[[、((、and if-then-else"


念のために:引用't1'は不要ですよね?t1変数t1が二重引用符で囲まれた算術命令とは対照的に、二重括弧で囲まれた条件式は単なるリテラル文字列です。[[ $varB == 't1' ]]つまり、とまったく同じ[[ $varB == t1 ]]ですよね?
ピーター-モニカの復活2017年

6

非常に移植可能なバージョン(レガシーbourneシェルにも):

if [ "$varA" = 1 -a \( "$varB" = "t1" -o "$varB" = "t2" \) ]
then    do-something
fi

これには、[シェルの種類に関係なく、多くても1つのサブプロセス(プロセス)を実行するという追加の品質があります。

交換する=-eq、変数に数値が含まれている場合、たとえば、

  • 3 -eq 03 本当ですが
  • 3 = 03は偽です。(文字列比較)

3

次に、if-then-elseステートメントの短いバージョンのコードを示します。

( [ $a -eq 1 ] || [ $b -eq 2 ] ) && echo "ok" || echo "nok"

次の点に注意してください。

  1. ||そして、&&(すなわち、丸括弧の間)状態であれば内部のオペランドは、論理オペランド(および/または)であります

  2. ||そして、&&オペランドは、外部の条件ならば、/それ以外の意味します

実際にはステートメントは言う:

if(a = 1 or b = 2)then "ok" else "nok"


括弧( ... )はサブシェルを作成します。{ ... }代わりに中括弧を使用したい場合があります。サブシェルで作成された状態は、呼び出し元には表示されません。
クリントパクル

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.