[[i równoważność wielkości liter w bash

13

Robi

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

zawsze zachowuj się tak samo jak

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

czy są jakieś gotchy?

PSkocik
źródło
1
Nie mogę znaleźć żadnych przypadków, gdy różnią się one, niezależnie od shoptustawień i wartości w $1ani pattern, ani $?potem. Jedyną różnicą jest to, że $1nie jest rozszerzana w wyniku, gdy działa pod xtrace.
Kusalananda

Odpowiedzi:

7

Tak, są one (prawie) całkowicie równoważne.


Szczegół

Wewnątrz [ … ]konstruktu:

=Operatora (lub także opcja nie Posix ==) sprawdza dopasowanie sznurka, nie pasuje do wzorca.

Wewnątrz [[ ]]konstruktu (z man bash):

Gdy używane są operatory == i! =, Ciąg po prawej stronie operatora jest uważany za wzorzec i dopasowywany zgodnie z zasadami opisanymi poniżej w części Dopasowywanie wzorców . Jeśli włączona jest opcja powłoki nocasematch , dopasowanie jest wykonywane bez względu na wielkość liter. Zwracana wartość to 0, jeśli łańcuch pasuje (==) lub nie pasuje (! =) Do wzorca, a 1 w przeciwnym razie. Każda część wzorca może być cytowana, aby wymusić dopasowanie go jako łańcucha.

Wewnątrz casekonstruktu (z man bash, zredagowanego i mojego podkreślenia):

słowo case na liście [[(] pattern [| pattern] ...) ;; ] ... esac
... próbuje dopasować go kolejno do każdego wzorca, stosując te same reguły dopasowywania , co w przypadku rozwijania nazw ścieżek (patrz Rozwijanie nazw ścieżek poniżej). … Każdy badany wzorzec jest rozszerzany za pomocą interpretacji tyldy, interpretacji parametrów i zmiennych, podstawienia arytmetycznego, zastępowania poleceń i podstawiania procesów. Jeśli włączona jest opcja powłoki nocasematch , dopasowanie jest wykonywane bez względu na wielkość liter.

Oba Pattern Matchingi Pathname Expansionsą używane w znaczeniu tego samego w podręczniku bash.

Jedyną różnicą, którą widzę w instrukcji, jest:

`[[ … ]]`                                   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

Które quote removalnie są wyraźnie wymienione w przypadku konstrukcji.
Który działa dokładnie dopasować to (dla [[ … ]]):

Każda część wzorca może być cytowana, aby wymusić dopasowanie go jako łańcucha.

Użyj tego, aby przetestować ostatni punkt (teraz zmienna nie jest wzorem):

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

Dlaczego prawie?

  1. Implikowany extglob:

    Od wersji 4.3 bash

    Gdy używane są operatory „==” i „! =”, Ciąg po prawej stronie operatora jest uważany za wzorzec i dopasowywany zgodnie z zasadami opisanymi poniżej w Dopasowywanie wzorców, tak jakby opcja powłoki extglob była włączona .

    Oznacza to, że wzorzec użyty z opcją extglob unset będzie działał inaczej w instrukcji case i wewnątrz [[konstrukcji po wersji bash 4.3.

  2. Implikowany |:

    Składnia wielkości liter jest następująca:

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

    Co oznacza, że ​​może istnieć kilka wzorów oddzielonych znakiem |(LUB).

    Lubię to:

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

    Który będzie pasował albo do łańcucha samych cyfr, albo tylko liter abcde, takich jak 1234lub aabee, ale nie 12alub b23.

    A [[będzie działać równorzędnie, jeśli zostanie użyte wyrażenie regularne (spójrz na 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
    

źródło