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

Posted

技术标签:

【中文标题】如何在 shell if 语句中表示多个条件?【英文标题】:How to represent multiple conditions in a shell if statement? 【发布时间】:2011-04-19 02:12:55 【问题描述】:

我想像这样表示多个条件:

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 行是显示 if ... 的行。

这种情况有什么问题?我猜() 有问题。

【问题讨论】:

你问的不是shell条件,而是test条件。您示例中的整个表达式由 test ([) 评估,而不是由 shell 评估。 shell 只评估[ 的退出状态。 另见***.com/questions/16203088/… 相关:Compound if statements with multiple expressions in Bash 【参考方案1】:

经典技巧(转义元字符):

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 运算符是 test 的 POSIX 规范的一部分,也称为 [,主要是为了向后兼容(因为它们是第 7 版 UNIX 中 test 的一部分,对于例如),但它们被 POSIX 明确标记为“过时”。 Bash(参见 conditional expressions)似乎抢占了 -a-o 的经典和 POSIX 含义,并使用其自己的带参数的替代运算符。


请注意,您可以使用更现代的[[ 运算符,但请注意,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 块中调用的函数中。

【讨论】:

很高兴知道转义括号有效;顺便说一句:在这种特殊情况下,甚至不需要括号,因为 -a 实际上比 -o 具有更高的优先级(与 shell 中的 &&|| 不同 - 但是,inside i> bash [[ ... ]] 条件, && also 的优先级高于 || )。如果您想避免使用 -a-o 以获得最大的健壮性和可移植性 - POSIX man page itself 建议 - 您还可以使用 subshel​​ls 进行分组:if ([ $g -eq 1 ] && [ "$c" = "123" ]) || ([ $g -eq 2 ] && [ "$c" = "456" ]) 很好的解决方案,但我喜欢没有括号和方括号的表格:if test "$g" -eq 1 -a "$c" = "123" || test "$g" -eq 2 -a "$c" = "456"; then ... 我有点晚了,但它仍然是一个热门搜索结果,所以我只想指出,使用 &&|| 也更可取,因为它的行为更像其他语言的条件,并让您短路条件。例如:if [ -n "$check_inodes" ] && [ "$(stat -f %i "/foo/bar")" = "$(stat -f %i "/foo/baz")" ]。这样做,如果check_inodes 为空,您可以避免两次调用stat,而更大、更复杂的测试条件必须在执行前处理 all 参数(如果您这样做也可能导致错误忘记那种行为)。【参考方案2】:

在 Bash 中:

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

【讨论】:

绝对是bash 中的最佳方法。顺便说一句:在这种特殊情况下甚至不需要括号,因为 inside [[ ... ]] conditionals && 实际上比 || 具有更高的优先级 - 不像 在这样的条件之外。 有什么方法可以找出这里匹配的条件吗?是第一个括号中的那个还是另一个? @Firelord:您需要将条件分成if / else 语句,并将thenfi 之间的代码放入一个函数中以避免重复它。在非常简单的情况下,您可以使用 case 语句和 ;& fallthrough(在 Bash 4 中)。 两个方括号的作用是什么? @peter:请看我的回答here、Conditional Constructs in the Bash Manual 和BashFAQ/31。【参考方案3】:

使用/bin/bash 将起作用:

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

【讨论】:

【参考方案4】:

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

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

【讨论】:

当我们在美元符号后使用大括号!!【参考方案5】:
$ 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

【讨论】:

那是一个无用的子shell。可以改用 ;【参考方案6】:

在 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

【讨论】:

【参考方案7】:
#!/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

【讨论】:

欢迎来到 Stack Overflow!这个问题是在寻找一个解释,而不仅仅是为了工作代码。您的回答没有为提问者提供任何见解,可能会被删除。请edit解释导致观察到的症状的原因。【参考方案8】:

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

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

【讨论】:

以上是关于如何在 shell if 语句中表示多个条件?的主要内容,如果未能解决你的问题,请参考以下文章

shell脚本中的if中多条件语句如何写。

在流程图中表示返回语句

如何在结构/流程图中表示多个线程

shell的awk中用if..else,怎么多条件嵌套

如何在 JavaScript 中表示浮点数? [复制]

如何在 Perl 中表示集合?