2008-09-19 13 views

Répondre

96

Citation lors de la mise FOO $ ne suffit pas. Vous devez citer la référence variable ainsi:

me$ FOO="BAR * BAR" 
me$ echo "$FOO" 
BAR * BAR 
+0

c'est mystérieux, pourquoi est-ce? que se passe-t-il? – tofutim

3
FOO='BAR * BAR' 
echo "$FOO" 
+0

Cela fonctionne, mais il est essentiel de ne pas changer les guillemets simples sur la première ligne de guillemets doubles. – finnw

+1

Non, ce n'est pas le cas, mais l'habitude d'utiliser des guillemets simples est préférable lorsque vous incluez des caractères spéciaux et que vous ne voulez pas de substitution. – tzot

3
echo "$FOO" 
3

Il peut être utile de prendre l'habitude d'utiliser printf plutôt que echo sur la ligne de commande.

Dans cet exemple, cela ne donne pas beaucoup d'avantages, mais cela peut être plus utile avec une sortie plus complexe.

FOO="BAR * BAR" 
printf %s "$FOO" 
+0

Pourquoi en enfer? printf est un processus séparé (au moins, pas un bash intégré) et l'utilisation de printf que vous démontrez n'a aucun avantage sur l'écho. – ddaa

+1

printf * est un bash intégré et je l'ai dit dans ma réponse "Dans cet exemple, il ne donne pas beaucoup d'avantages, mais il peut être plus utile avec une sortie plus complexe –

73

RÉPONSE À COURT

Comme d'autres l'ont dit - vous devez toujours citer les variables pour éviter des comportements étranges. Donc, utilisez echo "$ foo" au lieu de simplement echo $ foo.

RÉPONSE À LONG

je pense cet exemple mérite plus d'explications parce qu'il ya plus de choses que cela puisse paraître sur le visage de celui-ci.

je peux voir où votre confusion vient parce que, après que vous avez exécuté votre premier exemple vous avez probablement pensé à vous-même que la coquille est évidemment fait:

  1. extension des paramètres
  2. extension Nom du fichier

Donc, à partir de votre premier exemple:

me$ FOO="BAR * BAR" 
me$ echo $FOO 

A l'expansion des paramètres près avoir est équivalent à:

me$ echo BAR * BAR 

Et après extension de 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.

Alors vous avez probablement pensé à vous-même « si j'échapper au *, je peux empêcher l'extension de nom de fichier »

donc de votre deuxième exemple:

me$ FOO="BAR \* BAR" 
me$ echo $FOO 

Après l'expansion des paramètres devrait être équivalent à:

me$ echo BAR \* BAR 

après l'expansion du nom de fichier doit être équivalent à:

me$ echo BAR \* BAR 

Et si vous essayez de taper "echo BAR \ * BAR" directement dans la ligne de commande, il affichera en effet "BAR * BAR" car l'extension du nom de fichier est empêchée par l'échappement. Alors pourquoi utiliser $ foo ne fonctionne-t-il pas?

C'est parce qu'il y a une troisième expansion qui a lieu - Suppression de citation. De la suppression de devis manuel bash est:

Après les extensions précédentes, tous les non cotées occurrences des caractères « \ », « » », et « " » qui ne résultent d'une des extensions ci-dessus sont enlevés.

alors qu'est-ce qui se passe est lorsque vous tapez la commande directement dans la ligne de commande, le caractère d'échappement n'est pas le résultat d'une expansion précédente de sorte BASH il supprime avant de l'envoyer à la commande echo, mais le deuxième exemple, le "\ *" était le résultat d'une extension de paramètre précédente, donc il n'est pas supprimé En conséquence, echo reçoit "\ *" et c'est ce qu'il imprime.

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. À la fin, la conclusion dans le même - juste utiliser des citations. Je pensais juste que j'expliquerais pourquoi l'échappement, qui devrait logiquement fonctionner si seulement l'extension Parameter et Filename est en jeu, n'a pas fonctionné.

Pour une explication complète des extensions BASH, reportez-vous à:

http://www.gnu.org/software/bash/manual/bashref.html#Shell-Expansions

+0

Bonne réponse! Maintenant, je ne me sens pas je : – andyuk

+1

Il existe une utilité pour échapper les caractères spéciaux? –

+0

"vous devriez toujours citer les variables pour éviter les comportements étranges" - quand vous voulez les utiliser comme des chaînes – Angelo

37

Je vais ajouter un peu à ce vieux fil.

Généralement, vous utilisez

$ 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" 

Les * doit être transmis in extenso à curl, mais les mêmes problèmes se poseront. L'exemple ci-dessus ne fonctionnera pas (il s'étendra aux noms de fichiers dans le répertoire courant) et aucun ne le fera \*. Vous ne pouvez également pas citer $curl_opts car il sera reconnu comme une seule option (invalide) à curl.

curl: option -s --noproxy * -O: is unknown 
curl: try 'curl --help' or 'curl --manual' for more information 

Par conséquent, je recommande l'utilisation de la variable $GLOBIGNOREbash pour empêcher l'expansion des noms de fichiers tout à fait si elle est appliquée au modèle global, ou utiliser le set -f intégré drapeau.

#!/bin/bash 
GLOBIGNORE="*" 
curl_opts="-s --noproxy * -O" 
curl $curl_opts "$1" ## no filename expansion 

Application à 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 
+2

Seul 'set -f' a fonctionné dans mon cas –

+2

Bonne explication, merci! Mon utilisation est' SELECT * FROM etc.', ceci – knutole

+0

Merci d'avoir présenté la solution set -f! – hachre