[[и регистр эквивалентности в Bash

13

Имеет ли

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

всегда вести себя так же, как

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

или есть какие-то ошибки?

PSkocik
источник
1
Я не могу найти какие - либо случаи , когда они отличаются, независимо от shoptнастроек и значений $1или pattern, ни $?впоследствии. Единственное отличие состоит в том, что $1при работе под ним не раскрывается вывод xtrace.
Кусалананда

Ответы:

7

Да, они (почти) полностью эквивалентны.


подробность

Внутри [ … ]конструкции:

=Оператор (или даже вариант не-POSIX из ==) проверяет соответствие строки, а не соответствующий шаблон.

Внутри [[ ]]конструкции (от человека Баш):

Когда используются операторы == и! =, Строка справа от оператора считается шаблоном и сопоставляется в соответствии с правилами, описанными ниже в разделе «Сопоставление с шаблоном» . Если включена опция оболочки nocasematch , сопоставление выполняется без учета буквенных символов. Возвращаемое значение равно 0, если строка соответствует (==) или не соответствует (! =) Шаблону, и 1 в противном случае. Любая часть шаблона может быть заключена в кавычки, чтобы ее можно было сопоставить как строку.

Внутри caseконструкции (от man bash, отредактировано и выделено мое):

регистр слов в списке [[(] pattern [| pattern] ...) ;; ] ... esac
... пытается сопоставить его с каждым шаблоном по очереди, используя те же правила сопоставления, что и при расширении пути (см. Расширение пути ниже). … Каждый проверенный шаблон расширяется с использованием расширения тильды, расширения параметров и переменных, арифметического замещения, подстановки команд и замещения процесса. Если включена опция оболочки nocasematch , сопоставление выполняется без учета буквенных символов.

Оба Pattern Matchingи Pathname 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.
Который работает, чтобы точно соответствовать этому (для [[ … ]]):

Любая часть шаблона может быть заключена в кавычки, чтобы ее можно было сопоставить как строку.

Используйте это, чтобы проверить эту последнюю точку (теперь переменная не является шаблоном):

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

Почему почти?

  1. Неявный extglob:

    Начиная с версии 4.3 Bash

    Когда используются операторы '==' и '! =', Строка справа от оператора считается шаблоном и сопоставляется в соответствии с правилами, описанными ниже в разделе «Сопоставление с образцом» , как если бы была включена опция оболочки extglob .

    Это означает, что шаблон, используемый с опцией extglob unset, будет работать по-разному в операторе case и внутри [[конструкции после bash версии 4.3.

  2. Неявный |:

    Синтаксис для case:

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

    Это означает, что может быть несколько шаблонов, разделенных |(ИЛИ).

    Как это:

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

    Который будет соответствовать либо строке только цифр или только букв abcde, как 1234или aabee, но не 12aили b23.

    A [[будет работать аналогично, если используется регулярное выражение (смотрите var p3):

    #!/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

источник