【问题标题】:How to represent multiple conditions in a shell if statement?如何在 shell if 语句中表示多个条件?
【发布时间】: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 ... 的行。

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

【问题讨论】:

标签: bash shell unix


【解决方案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:请看我的回答hereConditional Constructs in the Bash ManualBashFAQ/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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-06-25
        • 2013-12-17
        • 1970-01-01
        • 2018-04-29
        • 1970-01-01
        • 2015-01-20
        • 1970-01-01
        • 2017-09-25
        相关资源
        最近更新 更多