par exemple.
me$ FOO="BAR * BAR"
me$ echo $FOO
BAR file1 file2 file3 file4 BAR
et en utilisant le caractère d'échappement "\":
me$ FOO="BAR \* BAR"
me$ echo $FOO
BAR \* BAR
Je fais évidemment quelque chose de stupide.
Comment puis-je obtenir la sortie "BAR * BAR"?
Citer lors de la définition de $ FOO ne suffit pas. Vous devez également citer la référence de la variable:
me$ FOO="BAR * BAR"
me$ echo "$FOO"
BAR * BAR
REPONSE COURTE
Comme d’autres l’ont dit, vous devez toujours citer les variables pour éviter tout comportement étrange. Donc, utilisez echo "$ foo" dans au lieu de echo $ foo.
RÉPONSE LONGUE
Je pense que cet exemple mérite une explication plus approfondie, car il se passe plus de choses qu'il n'y paraît.
Je peux voir d'où vient votre confusion, car après avoir donné votre premier exemple, vous vous êtes probablement dit que Shell était en train de le faire:
Donc, à partir de votre premier exemple:
me$ FOO="BAR * BAR"
me$ echo $FOO
Après l’extension du paramètre est équivalent à:
me$ echo BAR * BAR
Et après l'extension du nom de fichier est équivalent à:
me$ echo BAR file1 file2 file3 file4 BAR
Et si vous tapez juste echo BAR * BAR
dans la ligne de commande, vous verrez qu’ils sont équivalents.
Donc vous avez probablement pensé "si j'échappe au *, je peux empêcher l'expansion du nom de fichier"
Donc, à partir de votre deuxième exemple:
me$ FOO="BAR \* BAR"
me$ echo $FOO
Après le développement des paramètres doit être équivalent à:
me$ echo BAR \* BAR
Et après l'extension du nom de fichier devrait être équivalent à:
me$ echo BAR \* BAR
Et si vous essayez de saisir "echo BAR\* BAR" directement dans la ligne de commande, il affichera effectivement "BAR * BAR" car le développement du nom de fichier est empêché par l'échappement.
Alors pourquoi utiliser $ foo ne fonctionne pas?
C'est parce qu'il y a une troisième expansion qui a lieu - Enlèvement de devis. De la suppression manuelle des devis bash, vous obtenez:
Après les extensions précédentes, toutes les occurrences non citées des caractères "\", "" et "" qui ne résultaient pas de l’une des extensions ci-dessus sont supprimées.
Ainsi, lorsque vous tapez la commande directement dans la ligne de commande, le caractère d'échappement n'est pas le résultat d'une extension précédente. BASH le supprime avant de l'envoyer à la commande echo. Dans le deuxième exemple, le caractère "\ *" était le résultat d'une extension de paramètre précédente, il n'est donc PAS supprimé. En conséquence, l'écho reçoit "\ *" et c'est ce qu'il affiche.
Notez la différence entre le premier exemple - "*" n'est pas inclus dans les caractères qui seront supprimés par Suppression de devis.
J'espère que cela a du sens. En fin de compte la conclusion dans le même - il suffit d'utiliser des guillemets. Je pensais juste que j'expliquerais pourquoi échapper, ce qui devrait logiquement fonctionner si seuls les extensions Paramètre et Nom de fichier sont en jeu, ne fonctionnait pas.
Pour une explication complète des extensions BASH, reportez-vous à:
http://www.gnu.org/software/bash/manual/bashref.html#Shell-Expansions
Je vais ajouter un peu à ce vieux fil.
Habituellement, vous utiliseriez
$ echo "$FOO"
Cependant, j'ai eu des problèmes même avec cette syntaxe. Considérez le script suivant.
#!/bin/bash
curl_opts="-s --noproxy * -O"
curl $curl_opts "$1"
Le *
Doit être transmis textuellement à curl
, mais les mêmes problèmes se poseront. L'exemple ci-dessus ne fonctionnera pas (il développera les noms de fichiers du répertoire actuel) et \*
Non plus. Vous ne pouvez pas non plus citer $curl_opts
, Car elle sera reconnue comme une option unique (non valide) pour curl
.
curl: option -s --noproxy * -O: is unknown
curl: try 'curl --help' or 'curl --manual' for more information
Par conséquent, je recommanderais l'utilisation de la variable bash
$GLOBIGNORE
Pour empêcher l'expansion du nom de fichier si elle est appliquée au modèle global, ou utiliser l'indicateur intégré set -f
.
#!/bin/bash
GLOBIGNORE="*"
curl_opts="-s --noproxy * -O"
curl $curl_opts "$1" ## no filename expansion
En appliquant votre exemple original:
me$ FOO="BAR * BAR"
me$ echo $FOO
BAR file1 file2 file3 file4 BAR
me$ set -f
me$ echo $FOO
BAR * BAR
me$ set +f
me$ GLOBIGNORE=*
me$ echo $FOO
BAR * BAR
FOO='BAR * BAR'
echo "$FOO"
Il peut être intéressant de prendre l’habitude d’utiliser printf
plutôt que echo
sur la ligne de commande.
Dans cet exemple, cela ne présente pas beaucoup d'avantages, mais cela peut être plus utile avec des sorties plus complexes.
FOO="BAR * BAR"
printf %s "$FOO"
echo "$FOO"