Comment échapper à des modèles d'extension des noms de fichiers étendus dans les expressions cités?
-
22-08-2019 - |
Question
En plus des *
de base, les modèles de ?
et [...]
, la coque Bash fournit aux opérateurs de correspondance de motif étendu comme !(pattern-list)
( « répondant à tous sauf un des motifs donnés »). L'option shell extglob
doit être mis à les utiliser. Un exemple:
~$ mkdir test ; cd test ; touch file1 file2 file3
~/test$ echo *
file1 file2 file3
~/test$ shopt -s extglob # make sure extglob is set
~/test$ echo !(file2)
file1 file3
Si je passe une expression shell à un programme qu'il exécute dans un sous-shell, l'opérateur provoque une erreur. Voici un test qui exécute un sous-shell directement (ici, je suis l'exécution d'un autre répertoire pour faire l'expansion que ne se produise pas prématurément):
~/test$ cd ..
~$ bash -c "cd test ; echo *"
file1 file2 file3
~$ bash -c "cd test ; echo !(file2)" # expected output: file1 file3
bash: -c: line 0: syntax error near unexpected token `('
bash: -c: line 0: `cd test ; echo !(file2)'
J'ai essayé toutes sortes d'échapper, mais rien que je suis venu avec a fonctionné correctement. Je soupçonne aussi extglob
n'est pas réglé dans un sous-shell, mais ce n'est pas le cas:
~$ bash -c "shopt -s extglob ; cd test ; echo !(file2)"
bash: -c: line 0: syntax error near unexpected token `('
bash: -c: line 0: `cd test ; echo !(file2)'
Toute solution appréciée!
La solution
$ bash -O extglob -c 'echo !(file2)' file1 file3
Autres conseils
bash chaque ligne parse avant de l'exécuter, de sorte que « la extglob de shopt » ne sera pas pris effet lorsque bash est la syntaxe de valider englobement modèle. L'option ne peut pas être activée sur la même ligne. Voilà pourquoi la solution (de Randy Proctor) "bash -O extglob -c 'xyz'" fonctionne et est nécessaire.
Voici une autre façon, si vous voulez éviter eval
et vous devez être en mesure de tourner extglob sur et en dehors dans le sous-shell. Il suffit de mettre votre modèle dans une variable:
bash -c 'shopt -s extglob; cd test; patt="!(file2)"; echo $patt; shopt -u extglob; echo $patt'
donne cette sortie:
file1 file3
!(file2)
extglob a été mis en et hors service. Si la première echo
avait des guillemets autour du $patt
, il serait tout simplement cracher le motif comme le deuxième echo
(qui devrait probablement les guillemets).
Eh bien, je n'ai pas experince réel avec extglob , mais je peux l'obtenir pour travailler en enveloppant le echo
dans un eval
:
$ bash -c 'shopt -s extglob ; cd test ; eval "echo !(file2)"'
file1 file3