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?
`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]
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 à:
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
.
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:
$IFS
Sur les caractères que vous souhaitez fractionner.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
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`