シェルのifステートメントで複数の条件を表す方法は?


308

このような複数の条件を表現したいと思います。

if [ ( $g -eq 1 -a "$c" = "123" ) -o ( $g -eq 2 -a "$c" = "456" ) ]   
then  
    echo abc;  
else  
    echo efg;   
fi  

スクリプトを実行すると、次のように表示されます

syntax error at line 15: `[' unexpected, 

ここで、15行目は...を示すものです。

この状態の何が問題になっていますか?私は何かが間違っていると思います()


6
シェル条件ではなく、テスト条件について尋ねています。例の式全体は、シェルではなくtest[)によって評価されます。シェルはの終了ステータスのみを評価します[
2015年


回答:


381

古典的な手法(メタ文字のエスケープ):

if [ \( "$g" -eq 1 -a "$c" = "123" \) -o \( "$g" -eq 2 -a "$c" = "456" \) ]
then echo abc
else echo efg
fi

への参照を$g二重引用符で囲みました。これは一般的には良い習慣です。優先順位ので厳密には、括弧は必要ありません-aとは-o、それは彼らがなくても修正します。

ことを注意-aして-oオペレーターがためにPOSIX仕様の一部であるtest別名、[主に(彼らはの一部であったため、後方互換性のために、test例えば、第7版UNIXの場合)が、彼らが明示的にPOSIXよる「旧式」としてマークされています。bashは(参照条件式を)のための古典とPOSIXの意味を先取りするようだ-aと、-o引数を取る独自の代替事業者と。


少し注意して、よりモダンな[[演算子を使用できますが、BashとKorn Shell(たとえば)のバージョンが同じである必要はないことに注意してください。

for g in 1 2 3
do
    for c in 123 456 789
    do
        if [[ ( "$g" -eq 1 && "$c" = "123" ) || ( "$g" -eq 2 && "$c" = "456" ) ]]
        then echo "g = $g; c = $c; true"
        else echo "g = $g; c = $c; false"
        fi
    done
done

Mac OS XでBash 3.2.57を使用した実行例:

g = 1; c = 123; true
g = 1; c = 456; false
g = 1; c = 789; false
g = 2; c = 123; false
g = 2; c = 456; true
g = 2; c = 789; false
g = 3; c = 123; false
g = 3; c = 456; false
g = 3; c = 789; false

あなたには、変数を引用する必要はありません。[[あなたがそうであるように[、それは同じように別々のコマンドではないため[ですが。


古典的な質問ではないですか?

私はそう思っただろう。ただし、別の方法があります。

if [ "$g" -eq 1 -a "$c" = "123" ] || [ "$g" -eq 2 -a "$c" = "456" ]
then echo abc
else echo efg
fi

実際、autoconfツールまたは関連パッケージの「ポータブルシェル」のガイドラインを読んだ場合、この表記(「||」と「&&」を使用)が推奨されます。私はあなたがこれまでに行くことができると思います:

if [ "$g" -eq 1 ] && [ "$c" = "123" ]
then echo abc
elif [ "$g" -eq 2 ] && [ "$c" = "456" ]
then echo abc
else echo efg
fi

アクションがエコーと同じくらい簡単な場合、これは悪くありません。繰り返されるアクションブロックが複数行である場合、繰り返しが非常に面倒であり、以前のバージョンの1つが望ましいです。または、アクションを別のthenブロックで呼び出される関数にラップする必要があります。


9
エスケープされた括弧が機能することを知っておくのは良いことです。余談として、この特定のケースでは、括弧をも必要としない、ため、-a実際よりも高い優先順位有する-o(とは異なり、&&かつ||シェル内を-しかし、内部 bash [[ ... ]] の条件文&& また、より高い優先順位を有しています||)。あなたは避けたかった場合-a-o、最大堅牢性と移植性のために- POSIXのmanページそのものが示唆-あなたはまた、使用することができサブシェルをグループ化するために:if ([ $g -eq 1 ] && [ "$c" = "123" ]) || ([ $g -eq 2 ] && [ "$c" = "456" ])
mklement0

すべての括弧と括弧なしの形のような良い解決策が、私:if test "$g" -eq 1 -a "$c" = "123" || test "$g" -eq 2 -a "$c" = "456"; then ...
Mogens TrasherDK

私は少し遅れてこれまでだけど、私が使用していることだけでノートしたいので、それは、まだトップの検索結果です&&||、それはより多くの他の言語の条件文のように振る舞い、そしてあなたに短絡状態をすることができますようにも好適です。例:if [ -n "${check_inodes}" ] && [ "$(stat -f %i "/foo/bar")" = "$(stat -f %i "/foo/baz")" ]。このようにするcheck_inodesと、空の場合、への2回の呼び出しを回避できますstatが、より大きく複雑なテスト条件では、実行前にすべての引数を処理する必要があります(その動作を忘れると、バグが発生する可能性もあります)。
Haravikk

182

バッシュで:

if [[ ( $g == 1 && $c == 123 ) || ( $g == 2 && $c == 456 ) ]]

9
間違いなくでの最善のアプローチbash。余談ですが、この特定のケースでは、括弧は必要ありません。なぜなら、条件式の内側 は、そのような条件式の外側とは異なり、実際には優先順位が高いからです。[[ ... ]] &&||
mklement0 2014年

ここで一致する条件を見つける方法はありますか?最初の括弧内のものですか、それとも他のものですか?
Firelord、2015

1
@Firelord:条件をif/ elseステートメントに分割し、コードを間thenfi置いて関数を配置することで、繰り返しを回避する必要があります。非常に単純なケースではcase;&フォールスルー付きのステートメントを使用できます(Bash 4)。
追って通知があるまで一時停止。

1
2つの角括弧の目的は何ですか?
peterchaula 2017


37

/bin/bash以下を使用するとうまくいきます:

if [ "$option" = "Y" ] || [ "$option" = "y" ]; then
    echo "Entered $option"
fi

8

文字列変数にスペースがあり、存在を確認する場合は注意してください。正しく引用してください。

if [ ! "${somepath}" ] || [ ! "${otherstring}" ] || [ ! "${barstring}" ] ; then

1
ドル記号の後に中括弧を使用すると!!
YouAreAwesome 2015

6
$ g=3
$ c=133
$ ([ "$g$c" = "1123" ] || [ "$g$c" = "2456" ]) && echo "abc" || echo "efg"
efg
$ g=1
$ c=123
$ ([ "$g$c" = "1123" ] || [ "$g$c" = "2456" ]) && echo "abc" || echo "efg"
abc

2
それは役に立たないサブシェルです。{ ;}代わりに使用できます。
phk

2

文字列比較のbashでは、次の手法を使用できます。

if [ $var OP "val" ]; then
    echo "statements"
fi

例:

var="something"
if [ $var != "otherthing" ] && [ $var != "everything" ] && [ $var != "allthings" ]; then
    echo "this will be printed"
else
    echo "this will not be printed"
fi

0
#!/bin/bash

current_usage=$( df -h | grep 'gfsvg-gfslv' | awk {'print $5'} )
echo $current_usage
critical_usage=6%
warning_usage=3%

if [[ ${current_usage%?} -lt ${warning_usage%?} ]]; then
echo OK current usage is $current_usage
elif [[ ${current_usage%?} -ge ${warning_usage%?} ]] && [[ ${current_usage%?} -lt ${critical_usage%?} ]]; then
echo Warning $current_usage
else
echo Critical $current_usage
fi

3
Stack Overflowへようこそ!この質問は、単に機能するコードではなく、説明を求めています。あなたの回答は質問者に洞察を提供せず、削除される場合があります。観察された症状の原因を説明するように編集してください。
Toby Speight 2017年

0

2つ以上の条件を連鎖させることもできます。

if [ \( "$1" = '--usage' \) -o \( "$1" = '' \) -o \( "$1" = '--help' \) ]
then
   printf "\033[2J";printf "\033[0;0H"
   cat << EOF_PRINT_USAGE

   $0 - Purpose: upsert qto http json data to postgres db

   USAGE EXAMPLE:

   $0 -a foo -a bar



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