Ma question vient de Comment le stockage de l'expression régulière dans une variable shell évite-t-il les problèmes de citation de caractères spéciaux pour le shell? .
Pourquoi y a-t-il une erreur:
$ [[ $a = a|b ]] bash: syntax error in conditional expression: unexpected token `|' bash: syntax error near `|b'
À
[[ ... ]]
l' intérieur du deuxième opérande de=
devrait se trouver un motif de globulation.N'est-ce
a|b
pas un modèle de globbing valide? Pouvez-vous indiquer quelle règle de syntaxe il viole?Certains commentaires ci-dessous indiquent que cela
|
est interprété comme un tuyau.Puis changer
=
pour le modèle glob=~
pour le modèle regex faire|
fonctionner$ [[ $a =~ a|b ]]
J'ai appris de Learning Bash p180 dans mon post précédent qui
|
est reconnu comme pipe au début de l'interprétation, avant même toute autre étape d'interprétation (y compris l'analyse des expressions conditionnelles dans les exemples). Alors, comment peut-on|
être reconnu comme opérateur regex lors de l'utilisation=~
, sans être reconnu comme tuyau dans une utilisation non valide, tout comme lors de l'utilisation=
? Cela me fait penser que l'erreur de syntaxe dans la partie 1 ne signifie pas qu'elle|
est interprétée comme un canal.Chaque ligne que le shell lit à partir de l'entrée standard ou d'un script est appelée pipeline; il contient une ou plusieurs commandes séparées par zéro ou plusieurs caractères de canal (|). Pour chaque pipeline lu, le shell le décompose en commandes, configure les E / S pour le pipeline, puis effectue les opérations suivantes pour chaque commande (figure 7-1):
Merci.
|
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 lesshopt
configurations d'options où ce comportement est vu - si ce n'est que celles où ilextglob
est activé, par défaut ou configuration explicite, eh bien, nous y sommes.pattern='a|b'
puis développez sans$pattern
guillemets sur le RHS.Réponses:
Il n'y a pas de bonne raison
Doit signaler une erreur au lieu de tester si $ a est la
a|b
chaî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,bash
attend 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'extglob
option 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:
Est
echo a
canalisé versb
.a|b
n'est pas un MOT , c'est trois jetons: una
MOT , un|
jeton et un jetonb
MOT .Lorsqu'il est utilisé dans
[[ $a = a|b ]]
,bash
attend un MOT qu'il obtient (a
), mais trouve ensuite un|
jeton inattendu qui provoque l'erreur.Fait intéressant,
bash
ne se plaint pas:Parce que c'est maintenant un
a
jeton suivi d'un||
jeton suivi deb
, il est donc analysé de la même manière que:Qui teste qui
$a
esta
ou que lab
chaîne n'est pas vide.Maintenant en:
bash
ne 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'ila|b
s'agit d'un seul mot . Mais, depuis bash 3.2, si vous le faites:Cela ne correspond plus à l'
a|b
expression rationnelle, mais à l'a\|b
expression 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 ,
bash
doit 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
fonctionne maintenant,
non. Vous avez besoin:
Qui dans les versions précédentes de
bash
ne correspondrait pas correctement à la barre oblique inverse. Celui-là a été corrigé, maisNe correspond pas à la barre oblique inverse comme il le devrait par exemple. Parce que
bash
ne 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.Correspond à l'
a|b
expression rationnelle.Cela signifie que le
=~
peut également être ajouté à la commande[
/test
:(fonctionne également dans
yash
. Les=~
besoins doivent être citészsh
comme=something
est 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 avecksh93
(même sibash
c'était le shell qui est apparu en premier[[ =~ ]]
), mais vous pouvez toujours le faireBASH_COMPAT=31
oushopt -s compat31
pour revenir au comportement précédent (sauf que tandis[[ $a =~ a|b ]]
que retournerait une erreur enbash
3.1, il ne le fait plus dansbash -O compat31
les versions plus récentes debash
).J'espère que cela clarifie pourquoi j'ai dit que les règles prêtaient à confusion et pourquoi utiliser:
aide notamment à la portabilité vers d'autres coques.
la source
[[ $a = a|b ]]
.a|b
n'est pas une coquille WORD ici, c'est lea
,|
etb
jetons. Commeecho a|b
ne produit pasa|b
ou ne développe pas una|b
glob, vous devez le citer|
car c'est un caractère shell spécial qui n'est pas valide dans ce contexte.[[ $a = (a|b) ]]
fonctionnerait commeecho (a|b)
fonctionnerait comme(a|b)
un opérateur générique zsh.Sont globs standard ( "extension de nom de fichier"):
*
,?
et[ ... ]
.|
n'est pas un opérateur glob valide dans les paramètres standard (non extglob).Essayer:
la source
|
littéralement interprété? Pourquoi y a-t-il une erreur de syntaxe?|
n'est-ce pas un opérateur glob, donc n'est-il pas|
interprété littéralement sans être cité? Alors pourquoi y a-t-il une erreur de syntaxe?|
est un caractère de contrôle; il n'est jamais traité comme un caractère littéral de la même manière qu'une lettre ou un chiffre.[[ $a = a
n'est pas une commande valide dont la sortie peut être dirigée vers un autre processus (du moins c'est ce que le shell pensait que vous essayiez de faire).Si vous voulez une correspondance regex, le test serait:
la source