web-dev-qa-db-fra.com

Quelle est la différence entre echo `date`, echo" `date`" et echo '`date`'?

Quelle est la différence entre ces trois commandes?

echo `date`
echo "`date`"
echo '`date`'

Je suis confus sur les différences réelles. Je pense que lorsque le 'est autour, cela signifie qu'il s'agit d'une chaîne, donc l'écho afficherait littéralement la chaîne date au lieu d'afficher la date?

24
John

`date` va simplement se développer jusqu'à la sortie de la commande date. Cependant, il supprime les caractères d'espace supplémentaires aux endroits où il y a plus d'un caractère d'espace consécutif dans la sortie. (Cela est dû au fait que la substitution de commande est sujette au fractionnement de Word et à la façon dont la commande echo gère plusieurs arguments.)

Dans "` date` ", les guillemets doubles sont des guillemets faibles, donc ils développeront les variables (essayez" $ PWD ") et effectueront la substitution de commandes. Le résultat de l'expansion est transmis en tant qu'argument single à la commande echo, avec tous les espaces consécutifs inclus: c'est-à-dire que le fractionnement de Word est pas effectué.

Dans 'date`' , les guillemets simples sont des guillemets plus forts, donc ils ne permettront pas l'expansion des variables ou la substitution de commandes en leur sein.

Reportez-vous ce lien pour plus d'explications.

Modifié le premier point comme l'a correctement souligné Michael Suelmann dans le commentaire ci-dessous .

Tous les deux

echo `date`

et

echo "`date`"

affichera la date. Le résultat de ce dernier ressemble au résultat de l'exécution de date par lui-même.

Il y a cependant une différence: celui entouré de " citations " sera envoyé à echo comme un seul argument. Les guillemets encapsulent la sortie de la commande entière en un seul argument. Puisque echo affiche simplement ses arguments dans l'ordre, avec des espaces entre les deux, il sera fondamentalement le même.

Voici un exemple de la subtile différence:

echo `date`

produit:

Fri Nov 1 01:48:45 EST 2013

mais:

echo "`date`"

produit:

Fri Nov  1 01:48:49 EST 2013

Notez que les deux espaces après Nov ont été réduits à un sans les guillemets. En effet, le shell analyse chaque élément séparé par des espaces et envoie le résultat à l'écho sous forme de 6 arguments. Lorsque vous le citez, echo reçoit un seul argument et les guillemets conservent l'espace.

Cela devient beaucoup plus important dans les commandes autres que l'écho. Par exemple, imaginez une commande foo qui veut deux arguments: une date et une adresse e-mail.

Cela fonctionnera dans ce scénario:

foo "`date`" [email protected]

Mais cela confondra le script en lui envoyant 7 arguments:

foo `date` [email protected]
16
Jim Stewart

Dans les shells POSIX, `date` Est l'ancienne forme de substitution de commande. La syntaxe moderne est $(date).

Dans les deux cas, ils se développent jusqu'à la sortie de date avec les caractères de fin de ligne supprimés (à condition que la sortie ne contienne pas de caractères NUL).

Cependant, lorsqu'il n'est pas entre guillemets doubles et dans des contextes de liste (par exemple dans les arguments de commandes simples comme echo dans votre cas), cette expansion est en outre soumise à:

  1. Séparation des mots: c'est-à-dire la "sortie de date avec les caractères de retour à la ligne supprimés" est divisée selon à la valeur actuelle de la variable $IFS (contenant par défaut espace, tabulation et nouvelle ligne (et NUL avec zsh)) en plusieurs mots .

    Par exemple, si date affiche Fri 1 Nov 14:11:15 GMT 2013\n (Comme c'est souvent le cas dans une langue anglaise et dans un fuseau horaire britannique) et que $IFS Contient actuellement :, qui sera divisé en 3 mots : Fri 1 Nov 14, 11 et 15 GMT 2013.

  2. génération du nom de fichier (aka globbing ) (sauf avec zsh): c'est-à-dire, chaque mot résultant de la la division ci-dessus est recherchée pour les caractères génériques (*, ?, [...] bien que certains shells en aient plus), et étendue à la liste des noms de fichiers qui correspondent à ces modèles. Par exemple, si la sortie de date est ?%? 33 */*/* UVC 3432 (Comme c'est souvent le cas dans les paramètres régionaux vénusiens et le fuseau horaire UVC), et $IFS Est la valeur par défaut), cela se développe en tous les noms de fichiers non cachés à 3 caractères dans le répertoire courant dont le caractère central est %, 33, tous les fichiers non cachés dans tous les sous-répertoires non cachés de tous les sous-répertoires non cachés du répertoire courant, UVC et 3432.

C'est pourquoi:

  1. Vous devez toujours citer (avec des guillemets doubles) les substitutions de commandes, sauf si vous voulez la génération de nom de fichier ou effectué lors de son expansion
  2. Si vous voulez Fractionnement de mots , alors vous devez définir $IFS Sur les caractères que vous souhaitez fractionner.
  3. Si vous voulez Fractionnement de mots mais pas génération de nom de fichier , vous devez émettez un set +f pour le désactiver.

Les guillemets simples citent tout, donc les caractères de backtick doivent être pris littéralement.

Exemple (l'utilisation de -x Permet de voir plus facilement ce qui se passe):

$ bash --norc -x
bash-4.2$ IFS=:
+ IFS=:
bash-4.2$ echo `date`
++ date
+ echo 'Fri  1 Nov 14' 42 '33 GMT 2013'
Fri  1 Nov 14 42 33 GMT 2013
bash-4.2$ echo "`date`"
++ date
+ echo 'Fri  1 Nov 14:42:41 GMT 2013'
Fri  1 Nov 14:42:41 GMT 2013

bash-4.2$ cd /lib/modules
+ cd /lib/modules
bash-4.2$ export TZ=UVC LC_ALL=vs_VS
+ export TZ=UVC LC_ALL=vs_VS
+ TZ=UVC
+ LC_ALL=vs_VS
bash-4.2$ unset -v IFS     # get the default behaviour
+ unset -v IFS
bash-4.2$ echo `date`
++ date
+ echo '?%?' 33 3.10-2-AMD64/build/Arch 3.10-2-AMD64/build/include 3.10-2-AMD64/build/Makefile 3.10-2-AMD64/build/Module.symvers 3.10-2-AMD64/build/scripts 3.10-2-AMD64/kernel/Arch 3.10-2-AMD64/kernel/crypto 3.10-2-AMD64/kernel/drivers 3.10-2-AMD64/kernel/fs 3.10-2-AMD64/kernel/lib 3.10-2-AMD64/kernel/mm 3.10-2-AMD64/kernel/net 3.10-2-AMD64/kernel/sound 3.10-2-AMD64/source/Arch 3.10-2-AMD64/source/include 3.10-2-AMD64/source/Makefile 3.10-2-AMD64/source/scripts 3.10-2-AMD64/updates/dkms 3.10-3-AMD64/build/Arch 3.10-3-AMD64/build/include 3.10-3-AMD64/build/Makefile 3.10-3-AMD64/build/Module.symvers 3.10-3-AMD64/build/scripts 3.10-3-AMD64/kernel/Arch 3.10-3-AMD64/kernel/crypto 3.10-3-AMD64/kernel/drivers 3.10-3-AMD64/kernel/fs 3.10-3-AMD64/kernel/lib 3.10-3-AMD64/kernel/mm 3.10-3-AMD64/kernel/net 3.10-3-AMD64/kernel/sound 3.10-3-AMD64/source/Arch 3.10-3-AMD64/source/include 3.10-3-AMD64/source/Makefile 3.10-3-AMD64/source/scripts 3.10-3-AMD64/updates/dkms UVC 3432
?%? 33 3.10-2-AMD64/build/Arch 3.10-2-AMD64/build/include 3.10-2-AMD64/build/Makefile 3.10-2-AMD64/build/Module.symvers 3.10-2-AMD64/build/scripts 3.10-2-AMD64/kernel/Arch 3.10-2-AMD64/kernel/crypto 3.10-2-AMD64/kernel/drivers 3.10-2-AMD64/kernel/fs 3.10-2-AMD64/kernel/lib 3.10-2-AMD64/kernel/mm 3.10-2-AMD64/kernel/net 3.10-2-AMD64/kernel/sound 3.10-2-AMD64/source/Arch 3.10-2-AMD64/source/include 3.10-2-AMD64/source/Makefile 3.10-2-AMD64/source/scripts 3.10-2-AMD64/updates/dkms 3.10-3-AMD64/build/Arch 3.10-3-AMD64/build/include 3.10-3-AMD64/build/Makefile 3.10-3-AMD64/build/Module.symvers 3.10-3-AMD64/build/scripts 3.10-3-AMD64/kernel/Arch 3.10-3-AMD64/kernel/crypto 3.10-3-AMD64/kernel/drivers 3.10-3-AMD64/kernel/fs 3.10-3-AMD64/kernel/lib 3.10-3-AMD64/kernel/mm 3.10-3-AMD64/kernel/net 3.10-3-AMD64/kernel/sound 3.10-3-AMD64/source/Arch 3.10-3-AMD64/source/include 3.10-3-AMD64/source/Makefile 3.10-3-AMD64/source/scripts 3.10-3-AMD64/updates/dkms UVC 3432
bash-4.2$ echo "`date`"
++ date
+ echo '?%? 33 */*/* UVC 3432'
?%? 33 */*/* UVC 3432

Si la sortie contient des caractères NUL, alors le comportement varie de Shell à Shell: certains les suppriment, certains tronquent la sortie au premier caractère NUL, zsh les conserve mais notez que de toute façon les commandes externes ne peuvent pas prendre d'arguments contenant des NULs

3

Avec `date` vous obtenez la sortie de la date divisée en plusieurs mots, car la division des mots est effectuée après la substitution de commande.

Avec "` date` ", vous obtenez la sortie de date sous la forme d'un mot/paramètre car il existe une substitution de commande entre guillemets doubles, mais la sortie n'est pas analysée davantage. La même chose est valable avec une expansion variable comme "$ i" dans mon exemple ci-dessous.

Avec "date", vous obtenez une "date" littérale car il n'y a pas de substitution de commande entre guillemets simples.

Peut-être que les différences des 3 formes seront plus visibles de cette façon:

> for i in `date`; do echo "$i"; done
Fr
1.
Nov
12:25:30
CET
2013

> for i in "`date`"; do echo "$i"; done
Fr 1. Nov 12:25:38 CET 2013

> for i in '`date`'; do echo "$i"; done
`date`
0
Michael Suelmann