如何在if语句中表示多个条件?


307

我想代表多个条件,例如:

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[)而不是shell 求值的。Shell仅评估的退出状态[
ceving 2015年


Answers:


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使得它纠正,甚至没有他们。

请注意,-aand -o运算符是testaka 的POSIX规范的一部分[,主要是为了向后兼容(例如,因为它们是test7th Edition 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

在动作像回声一样微不足道的地方,这还不错。当要重复的动作块为多行时,重复会很痛苦,并且较早的版本之一是可取的-否则您需要将动作包装到在不同then块中调用的函数中。


9
很高兴知道转义括号会起作用;顺便说一句:在这种特殊情况下,括号甚至没有必要的,因为-a实际上的优先级高于-o(不像&&||在外壳-然而,内部 bash [[ ... ]] 条件句&& 有优先级高于||)。如果您想要避免这种情况-a-o获得最大的鲁棒性和可移植性(这是POSIX手册页本身所建议的),则也可以使用子shell进行分组:if ([ $g -eq 1 ] && [ "$c" = "123" ]) || ([ $g -eq 2 ] && [ "$c" = "456" ])
mklement0 2014年

好的解决方案,但是我喜欢没有所有括号和括号的表格: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为空,则避免两次调用stat,而较大,复杂的测试条件必须在执行之前处理所有参数(如果忘记了这种行为,也可能导致错误)。
哈拉维克

182

在Bash中:

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

9
绝对是最好的方法bash。顺便说一句:在这种特殊情况下,甚至不需要括号,因为内部 [[ ... ]] 条件条件 &&实际上比||-不同于外部条件条件具有更高的优先级。
mklement0 2014年

有没有一种方法可以找出此处匹配的条件?是第一个括号中的一个还是另一个?
Firelord

1
@Firelord:您需要将条件分成if/ else语句,并在它们之间添加代码thenfi放入函数中,以免重复。在非常简单的情况下,您可以使用case带有;&fallthrough 的语句(在Bash 4中)。
暂停,直到另行通知。

1
两个方括号的目的是什么?
peterchaula


37

使用/bin/bash以下方法将起作用:

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

8

如果字符串变量中有空格并检查是否存在,请小心。确保正确引用它们。

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

1
当我们在美元符号后使用花括号!!
YouAreAwesome

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
那是没用的子shell。{ ;}可以代替使用。
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

0

您也可以链接两个以上的条件:

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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.