[[et équivalence de cas dans bash

13

Est-ce que

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

se comportent toujours comme

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

ou y a-t-il des problèmes?

PSkocik
la source
1
Je ne trouve aucun cas où ils diffèrent, quels que soient les shoptparamètres et les valeurs dans $1ou pattern, ni $?après. La seule différence est qu'il $1n'est pas développé dans la sortie lors de l'exécution sous xtrace.
Kusalananda

Réponses:

7

Oui, ils sont (presque) complètement équivalents.


Détail

À l'intérieur d'une [ … ]construction:

L' =opérateur (ou même l'option non posix de ==) teste la correspondance des chaînes, pas la correspondance des modèles.

A l'intérieur d'une [[ ]]construction (de man bash):

Lorsque les opérateurs == et! = Sont utilisés, la chaîne à droite de l'opérateur est considérée comme un modèle et mise en correspondance selon les règles décrites ci-dessous sous Correspondance de modèle . Si l' option shell nocasematch est activée, la correspondance est effectuée sans tenir compte de la casse des caractères alphabétiques. La valeur de retour est 0 si la chaîne correspond à (==) ou ne correspond pas (! =) Au modèle, et 1 sinon. N'importe quelle partie du modèle peut être citée pour forcer sa correspondance sous forme de chaîne.

A l'intérieur d'une caseconstruction (de man bash, édité et mis en évidence le mien):

mot de casse dans la liste [[(] motif [| motif] ...) ;; ] ... esac
... essaie de le faire correspondre à chaque modèle à son tour, en utilisant les mêmes règles de correspondance que pour l' expansion du nom de chemin (voir Expansion du nom de chemin ci-dessous). … Chaque modèle examiné est développé en utilisant l'expansion de tilde, l'expansion de paramètres et de variables, la substitution arithmétique, la substitution de commande et la substitution de processus. Si l' option shell nocasematch est activée, la correspondance est effectuée sans tenir compte de la casse des caractères alphabétiques.

Les deux Pattern Matchinget Pathname Expansionsont utilisés pour signifier la même chose dans le manuel bash.

La seule différence que je peux voir dans le manuel est:

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

Ce quote removaln'est pas explicitement répertorié pour la construction de cas.
Qui fonctionne pour correspondre exactement à cela (pour le [[ … ]]):

N'importe quelle partie du modèle peut être citée pour forcer sa correspondance sous forme de chaîne.

Utilisez ceci pour tester ce dernier point (maintenant la variable n'est plus un modèle):

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

Pourquoi presque?

  1. Implicite extglob:

    Depuis la version 4.3 de bash

    Lorsque les opérateurs '==' et '! =' Sont utilisés, la chaîne à droite de l'opérateur est considérée comme un modèle et mise en correspondance selon les règles décrites ci-dessous dans Correspondance de modèle, comme si l'option shell extglob était activée .

    Cela signifie qu'un modèle utilisé avec l'option extglob unset fonctionnera différemment dans une instruction case et dans une [[construction après la version 4.3 de bash.

  2. Implicite |:

    La syntaxe de la casse est:

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

    Ce qui signifie qu'il peut y avoir plusieurs motifs séparés par un |(OU).

    Comme ça:

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

    Qui correspondra soit à une chaîne composée uniquement de chiffres, soit uniquement de lettres abcde, comme 1234ou aabee, mais pas 12aou b23.

    A [[fonctionnera de manière équivalente si des expressions rationnelles (regardez var p3) sont utilisées:

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

la source