[[e equivalenza del caso in bash


13

fa

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

comportarsi sempre come

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

o ci sono dei gotcha?


1
Non riesco a trovare casi in cui differiscono, indipendentemente dalle shoptimpostazioni e dai valori in $1o pattern, né in $?seguito. L'unica differenza è che $1non si espande nell'output quando si esegue sotto xtrace.
Kusalananda

Risposte:


7

Sì, sono (quasi) completamente equivalenti.


Dettaglio

All'interno di un [ … ]costrutto:

L' =operatore (o anche l'opzione non posix di ==) verifica la corrispondenza della stringa, non la corrispondenza del modello.

All'interno di un [[ ]]costrutto (da man bash):

Quando vengono utilizzati gli operatori == e! =, La stringa a destra dell'operatore viene considerata un motivo e abbinata secondo le regole descritte di seguito in Corrispondenza dei motivi . Se l' opzione shell nocasematch è abilitata, la corrispondenza viene eseguita indipendentemente dal caso dei caratteri alfabetici. Il valore restituito è 0 se la stringa corrisponde (==) o non corrisponde (! =) Al modello e 1 in caso contrario. Qualsiasi parte del motivo può essere quotata per forzare la corrispondenza con una stringa.

All'interno di un casecostrutto (da man bash, a cura di ed enfasi mio):

la parola maiuscola nell'elenco [[(] modello [| modello] ...) ;; ] ... ESAC
... cerca di far corrispondere contro ogni modello, a sua volta, usando le stesse corrispondenti regole come per espansione di percorso (vedi Espansione di percorso di seguito). ... Ogni modello esaminato viene espanso utilizzando l'espansione della tilde, l'espansione di parametri e variabili, la sostituzione aritmetica, la sostituzione dei comandi e la sostituzione dei processi. Se l' opzione shell nocasematch è abilitata, la corrispondenza viene eseguita indipendentemente dal caso dei caratteri alfabetici.

Entrambi Pattern Matchinge Pathname Expansionsono usati per significare lo stesso nel manuale di bash.

L'unica differenza che posso vedere nel manuale è:

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

Ciò quote removalnon è elencato esplicitamente per il costrutto case.
Che funziona esattamente per questo (per il [[ … ]]):

Qualsiasi parte del motivo può essere quotata per forzare la corrispondenza con una stringa.

Usa questo per testare quest'ultimo punto (ora la variabile non è un modello):

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

Perché quasi?

  1. Implicito extglob:

    Dalla versione 4.3 di bash

    Quando vengono utilizzati gli operatori '==' e '! =', La stringa a destra dell'operatore viene considerata un modello e abbinata secondo le regole descritte di seguito in Pattern Matching, come se l'opzione shell extglob fosse abilitata .

    Ciò significa che un modello utilizzato con l'opzione extglob unset funzionerà in modo diverso in un'istruzione case e all'interno di un [[costrutto dopo bash versione 4.3.

  2. Implicito |:

    La sintassi per case è:

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

    Ciò significa che potrebbero esserci diversi modelli separati da un |(OR).

    Come questo:

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

    Che corrisponderà a una stringa di soli numeri o solo lettere in abcde, come 1234o aabee, ma non 12ao b23.

    A [[funzionerà in modo equivalente se si usano regex (guarda 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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.