【问题标题】:IF statement multiple and or conditionsIF 语句多个 and or 条件
【发布时间】:2016-10-14 21:11:03
【问题描述】:

我在 bash 中使用带有多个条件的 if 语句。

如何减少以下行语法。从你的设计角度来看,它看起来不错。

 if [ "$1" != "-l" ] && [ "$1" != "-a" ] && [ "$1" != "-h" ] && [ "$1" != "" ] && [ "$1" =  "-d" ] || [ "$1" = "-mv" ] || [ "$1" = "-dv" ] || [ "$1" = "-mr" ] || [ "$1" = "-dr" ];

谢谢

【问题讨论】:

标签: linux bash shell


【解决方案1】:

使用模式匹配。

if [[ $1 && $1 != -[lah] && $1 == -@(d|mv|dv|mr|dr) ]]; then

@(...) 是扩展模式的一个示例,在最新版本的bash 中默认情况下应在[[ ... ]] 内识别。如果您的版本不是最新版本,请将 shopt -s extglob 添加到脚本的开头。


事实上,你可以放弃$1 && $1 != -[lah],因为$1 == -@(...) 的真实性暗示了它的真实性。

if [[ $1 == -@(d|mv|dv|mr|dr) ]]; then

您也可以只使用符合 POSIX 的 case 语句:

case $1 of
 -d|-mv|-dv|-mr|-dr) echo good option ;;
 *) echo bad option ;;
esac

【讨论】:

    【解决方案2】:

    您可以为匹配和不匹配的值创建 2 个数组,并检查元素 $1 是否匹配数组中的任何元素,如下所示。

    nonmatch_array=( "-l" "-a" "-h" "" )
    match_array=(  "-d" "-mv" "-dv" "-mr" "-dr" )
    
    if [ `echo ${match_array[@]} | grep "$1"` ] || ! [ `echo ${nonmatch_array[@]} | grep "$1"` ] ; then 
        echo "is in array"
    else 
        echo "is not in array"
    fi
    

    希望它对你有用。

    【讨论】:

    • grep -q 总是什么都不发出,[ `...` ] 正在评估你的... 的标准输出作为测试(如果它是一个对测试命令没有意义的单词,检查那个单词是或不为空;但对于grep -q,它始终为空)。
    • @CharlesDuffy:我的错,不知何故错过了......更新了答案。感谢您的关注。
    • 这里还有待改进——使用grep非常慢;考虑重写以使用关联数组在 O(1) 时间内完成所有正在进行的测试。
    • ...或者,即使您不这样做,[[ $string = $target ]] 也会告诉您$string 是否匹配$target,这比调用grep 快得多。 (另外,grep 正在寻找子字符串,但如果 OP 希望 nonmatch_array 为空,则 everything"" 的子字符串,因此这显然是不正确的解释。
    • 同意模式匹配。但是在子字符串匹配的情况下,它也可以匹配其他字符串,这不是必需的。根据 OP 的问题,他想精确匹配。
    【解决方案3】:

    首先尝试将代码的长度限制在 1 行。

    if [  [ "$1" != "-l" ] 
       && [ "$1" != "-a" ]
       && [ "$1" != "-h" ] 
       && [ -n "$1" ] 
       && ( [ "$1" = "-d" ]
       || [ "$1" = "-mv" ]
       || [ "$1" = "-dv" ]
       || [ "$1" = "-mr" ]
       || [ "$1" = "-dr" ] ) ];
    

    我添加了大括号,以明确您对 or 的含义。

    现在您可以使用正则表达式组合所有匹配项:

       if [[ ! ("$a" =~ ^-(l|a|h|d|)$)
          &&    "$a" =~ ^-(mv|dv|mr|dr)$ ]]; then
          echo "Yes $a matches"
       fi
    

    但请重新考虑您正在测试的内容。该测试仅在匹配-mv/-dv/-mr/-dr 时为真,因此您无需测试选项lah

       if [[ "$a" =~ ^-(d|mv|dv|mr|dr)$ ]]; then
          echo "Yes $a matches"
       fi
    

    您可以使用变量来提取选项:

       options="d|mv|dv|mr|dr"
       if [[ "$a" =~ ^-(${options})$ ]]; then
          echo "Yes $a matches"
       fi
    

    每当代码变得难以阅读时(对于长代码或重复语句也是如此),您应该考虑使用函数。
    下一个函数很短,但很难阅读:

    options="d|mv|dv|mr|dr"
    function checkoption1 {
       [[ "$a" =~ ^-(${options})$ ]]
    }
    checkoption1 "$a" &&
       echo "Yes $a matches"
    

    我会选择稍微冗长的函数。我将包含您对 lah 的原始测试,以显示可能性。

    # checkoption return 0 for match,
    # returns 1 for forbidden option
    # returns 2 for undefined option
    function checkoption2 {
       case "$1" in
          -d|-mv|-dv|-mr|-dr) return 0 ;;
          -l|-a|-h|"")  return 1;;
          *) return 2;;
       esac
    }
    checkoption2 "$a" &&
       echo "Yes $a matches"
    

    在接受您的代码之前,您应该进行一些测试。
    我用一个小循环做了一些测试(现在所有答案都在一起)

    function checkoption1 {
       [[ "$a" =~ ^-(${options})$ ]]
    }
    
    # checkoption return 0 for match,
    # returns 1 for forbidden option
    # returns 2 for undefined option
    function checkoption2 {
       case "$1" in
          -d|-mv|-dv|-mr|-dr) return 0 ;;
          -l|-a|-h|"")  return 1;;
          *) return 2;;
       esac
    }
    
    for a in -mv mv -mvx -ms -mr -dr; do
           if [[ ! ("$a" =~ ^-(l|a|h|)$)
              &&    "$a" =~ ^-(d|mv|dv|mr|dr)$ ]]; then
              echo "Yes $a matches"
           fi
           if [[ "$a" =~ ^-(d|mv|dv|mr|dr)$ ]]; then
              echo "Yes $a matches"
           fi
           options="d|mv|dv|mr|dr"
           if [[ "$a" =~ ^-(${options})$ ]]; then
              echo "Yes $a matches"
           fi
           checkoption1 "$a" &&
              echo "Yes $a matches"
           checkoption2 "$a" &&
              echo "Yes $a matches 2"
     done
    

    【讨论】:

    • 我很确定其中一些是不可移植的,如果完全正确的话——例如嵌套的[s,或嵌套上下文中的本机逻辑运算符(例如&&)。使用( ... ) 而不是{ ...; } 进行分组会带来不小的效率损失。
    猜你喜欢
    • 2014-08-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-24
    • 1970-01-01
    • 2018-04-12
    • 1970-01-01
    • 2014-01-17
    相关资源
    最近更新 更多