[[和bash中的大小写对等


13

是否

if [[ "$1" = pattern ]]; then
    hook
fi

总是表现与

case "$1" in
    pattern) hook;;
esac

还是有陷阱?


1
无论shopt$1或中pattern,还是$?之后的设置和值,我都找不到它们不同的情况。唯一的区别是,$1在下运行时,输出不会扩展xtrace
库萨兰达

Answers:


7

是的,它们(几乎)完全等效。


详情

内部[ … ]构造:

=操作者(或甚至非POSIX选项==)测试字符串匹配,而不是模式匹配。

内部[[ ]]构造(来自man bash):

当使用==和!=运算符时,该运算符右边的字符串被视为一种模式,并根据以下“模式匹配”下所述的规则进行匹配。如果启用了shell 选项nocasematch,则执行匹配时将不考虑 字母字符的大小写。如果字符串匹配(==)或不匹配(!=)模式,则返回值为0,否则返回1。可以引用模式的任何部分以强制将其匹配为字符串。

内部case构造(来自man bash,编辑并强调我的):

[[(]模式[|模式] ...)列表中的大小写单词;] ... ESAC
...尝试匹配它反过来每个图案,使用相同的匹配规则作为用于路径扩展(见下文路径名扩展)。…使用波浪号扩展,参数和变量扩展,算术替换,命令替换和进程替换来扩展每个检查的模式。如果启用了shell 选项nocasematch,则执行匹配时将不考虑字母字符的大小写

双方Pattern MatchingPathname Expansion用来表示bash的手册中的一样。

我在手册中看到的唯一区别是:

`[[ … ]]`                                   case
tilde  expansion                            tilde expansion
parameter and variable expansion            parameter and variable expansion
arithmetic expansion                        arithmetic substitution
command substitution                        command substitution
process substitution                        process substitution
quote removal

quote removal是没有明确列出的情况下构造。
可以完全匹配的方法(针对[[ … ]]):

可以引用模式的任何部分以强制将其匹配为字符串。

使用它来测试最后一点(现在变量不是模式):

case "$1" in
  "$pattern") echo case match
esac

为什么差不多?

  1. 隐式extglob

    bash版本4.3开始

    当使用'=='和'!='运算符时,该运算符右边的字符串被视为一种模式,并根据以下“模式匹配”中所述的规则进行匹配,就好像启用了extglob shell选项一样

    这意味着,未extglob 设置选项的模式[[在bash版本4.3之后的case语句中和内部构造中的工作方式将有所不同。

  2. 隐式|

    case的语法为:

    case word in [ [(] pattern [ | pattern ] ... ) list ;; ] ... esac

    这意味着可能存在多个由|(OR)分隔的模式。

    像这样:

    shopt -s extglob;      p1="+([0-9])";       p2="+([abcde])"
    
    case "$1" in
        $p1|$p2)    echo "or case match" ; ;;
    esac

    它将匹配仅包含数字或仅包含字母的字符串abcde,例如1234aabee,但不匹配12ab23

    [[如果使用正则表达式(请参见var p3), A 将等效工作:

    #!/bin/bash
    
    shopt -s extglob           ### Use extended globbing.
    shopt -s globasciiranges   ### The range [a-z] will expand to [abcdefghijklmnopqrstuvwxyz].
    
    pattern="+([0-9])"
    p1="+([0-9])"
    p2="+([a-z])"
    p3="^([0-9]+|[a-z]+)$"
    
    case "$1" in
        $pattern)   echo case1 match ; ;&
        $p1|$p2)    echo case2 match ; ;;
    esac
    
    [[ "$1" == $pattern ]] && echo if1 match
    [[ "$1" =~ $p3 ]] && echo if2 match
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.