Il n'y a pas de bonne raison
[[ $a = a|b ]]
Doit signaler une erreur au lieu de tester si $ a est la a|bchaîne, tandis [[ $a =~ a|b ]]que ne renvoie pas d'erreur.
La seule raison est que |c'est généralement (extérieur et intérieur [[ ... ]]) un caractère spécial. Dans cette [[ $a =position, bashattend un type de jeton qui est un MOT normal comme les arguments ou les cibles des redirections dans une ligne de commande shell normale (mais comme si l' extgloboption avait été activée depuis bash 4.1).
(par WORD ici, je me réfère à un mot dans une grammaire de shell hypothétique comme celle décrite par la spécification POSIX , c'est quelque chose que le shell analyserait comme un jeton dans une ligne de commande de shell simple, pas une autre définition de mots comme l'anglais l' une d'une séquence de lettres ou d' une séquence de caractères non-espacement. foo"bar baz", $(echo x y)sont deux tels WORD s).
Dans une ligne de commande shell normale:
echo a|b
Est echo acanalisé vers b. a|bn'est pas un MOT , c'est trois jetons: un a MOT , un |jeton et un jeton b MOT .
Lorsqu'il est utilisé dans [[ $a = a|b ]], bashattend un MOT qu'il obtient ( a), mais trouve ensuite un |jeton inattendu qui provoque l'erreur.
Fait intéressant, bashne se plaint pas:
[[ $a = a||b ]]
Parce que c'est maintenant un ajeton suivi d'un ||jeton suivi de b, il est donc analysé de la même manière que:
[[ $a = a || b ]]
Qui teste qui $aest aou que la bchaîne n'est pas vide.
Maintenant en:
[[ $a =~ a|b ]]
bashne peut pas avoir la même règle d'analyse. Avoir la même règle d'analyse signifierait que ce qui précède donnerait une erreur et qu'il faudrait citer cela |pour s'assurer qu'il a|bs'agit d'un seul mot . Mais, depuis bash 3.2, si vous le faites:
[[ $a =~ 'a|b' ]]
Cela ne correspond plus à l' a|bexpression rationnelle, mais à l' a\|bexpression rationnelle. C'est-à-dire que la citation du shell a pour effet secondaire de supprimer la signification spéciale des opérateurs d'expression régulière. C'est une fonctionnalité, donc le comportement est similaire à [[ $a = "?" ]]celui, mais les modèles génériques (utilisés dans [[ $a = pattern ]]) sont des MOTS shell (utilisés dans les globes par exemple), contrairement aux expressions rationnelles.
Donc , bashdoit traiter tous les opérateurs de telle expression rationnelle qui sont par ailleurs normalement des caractères shell spéciaux comme |, (, )différemment lors de l' analyse d' un argument de l' =~opérateur.
Notez cependant que
[[ $a =~ (ab)*c ]]
fonctionne maintenant,
[[ $a =~ [)}] ]]
non. Vous avez besoin:
[[ $a =~ [\)}] ]]
[[ $a =~ [')'}] ]]
Qui dans les versions précédentes de bashne correspondrait pas correctement à la barre oblique inverse. Celui-là a été corrigé, mais
[[ $a =~ [^]')'] ]]
Ne correspond pas à la barre oblique inverse comme il le devrait par exemple. Parce que bashne parvient pas à réaliser que )se trouve entre crochets, échappe donc à )pour aboutir à une [^]\)]expression rationnelle qui correspond à n'importe quel caractère mais ], \et ).
ksh93 a des bogues bien pires sur ce front.
Dans zsh, c'est un mot shell normal qui est attendu et le fait de citer des opérateurs regexp n'affecte pas la signification des opérateurs regexp.
[[ $a =~ 'a|b' ]]
Correspond à l' a|bexpression rationnelle.
Cela signifie que le =~peut également être ajouté à la commande [/ test:
[ "$a" '=~' 'a|b' ]
test "$a" '=~' 'a|b'
(fonctionne également dans yash. Les =~besoins doivent être cités zshcomme =somethingest un opérateur shell spécial là-bas).
bash 3.1 se comportait comme auparavant zsh. Il a changé en 3.2, vraisemblablement pour s'aligner avec ksh93(même si bashc'était le shell qui est apparu en premier [[ =~ ]]), mais vous pouvez toujours le faire BASH_COMPAT=31ou shopt -s compat31pour revenir au comportement précédent (sauf que tandis [[ $a =~ a|b ]]que retournerait une erreur en bash3.1, il ne le fait plus dans bash -O compat31les versions plus récentes de bash).
J'espère que cela clarifie pourquoi j'ai dit que les règles prêtaient à confusion et pourquoi utiliser:
[[ $a =~ $var ]]
aide notamment à la portabilité vers d'autres coques.
|est spécial) est activée par défaut dans la partie droite de[[ $var = $pattern ]]. Il serait intéressant d'isoler les versions et lesshoptconfigurations d'options où ce comportement est vu - si ce n'est que celles où ilextglobest activé, par défaut ou configuration explicite, eh bien, nous y sommes.