43 votes

Différence entre ${} et $() dans un script shell

$ echo $(date)
Jeu 2 Juil 16:33:11 SGT 2015
$ echo ${date}

$ name=foo
$ echo $(name)
ksh: name:  not found

$ echo ${name}
foo

Il semble que ${variable} est identique à $variable, tandis que $() sert à exécuter une commande. Pourquoi utiliser ${} alors?

62voto

**$(**_command_**)** est la "substitution de commande". Comme vous semblez le comprendre, elle exécute la commande, capture sa sortie, et l'insère dans la ligne de commande contenant le $(…); par exemple,

$ ls -ld $(date +%B).txt
-rwxr-xr-x  1 Noob Noob    867 2 juil 11:09 July.txt

**${**_paramètre_**}** est la "substitution de paramètre". Beaucoup d'informations peuvent être trouvées dans la page de manuel de la shell, bash(1), sous le titre "Extension de paramètre":

**${**_paramètre_**}**

La valeur du paramètre est substituée. Les accolades sont nécessaires lorsque paramètre est un paramètre positionnel avec plus d'un chiffre, ou lorsque paramètre est suivi d'un caractère qui ne doit pas être interprété comme faisant partie de son nom.

Pour les paramètres positionnels, voir "Paramètres Positionnels" ci-dessous. Dans son utilisation la plus courante, comme indiqué dans les autres réponses, paramètre est un nom de variable. La forme ${…}, comme indiqué à la fin du paragraphe ci-dessus, vous permet d'obtenir la valeur d'une variable (c'est-à-dire **$**_nom_de_variable_) et de la suivre immédiatement avec une lettre, un chiffre ou un trait de soulignement:

$ animal=chat
$ echo $animaux
                                _\# Aucune variable de ce nom_ "animaux".
$ echo ${animal}s
chats
$ echo $nourriture\_animal
                                _\# Aucune variable de ce nom_ "nourriture\_animal".
$ echo ${animal}\_nourriture
nourriture\_chat

Vous pouvez également le faire avec des guillemets:

$ echo "$animal"s
chats

Ou, comme exercice d'options, vous pourriez utiliser une deuxième variable:

$ pluriel=s
$ echo $animal$pluriel
chats

Mais ce n'est que l'étape 1. Le paragraphe suivant de la page de manuel est intéressant, bien qu'un peu cryptique:

Si le premier caractère de paramètre est un point d'exclamation (!), un niveau d'indirection de variable est introduit. Bash utilise la valeur de la variable formée à partir du reste de paramètre comme nom de la variable; cette variable est ensuite développée et cette valeur est utilisée dans le reste de la substitution, plutôt que la valeur de paramètre lui-même. Cela est connu sous le nom d'expansion indirecte. …<i>(exceptions)</i>… Le point d'exclamation doit immédiatement suivre la parenthèse gauche afin d'introduire l'indirection.

Je ne suis pas sûr de pouvoir rendre cela plus clair sinon par exemple:

$ animal=chat
$ echo $animal
chat
$ chat=chat de gouttière
$ echo $chat
chat de gouttière
$ echo ${!animal}
chat de gouttière                               _\# Si_ $animal _est_ "chat"_, alors_ ${!animal} _est_ $chat_, c'est-à-dire_ "chat de gouttière"

Appelons cela l'étape 1½. Il y a beaucoup de choses intéressantes que vous pouvez faire à l'étape 2:

$ animal=chat
$ echo ${#animal}
3                               _\# Longueur de la chaîne_
$ echo ${animal/at/ow}
vache                             _\# Substitution_

Vous ne pouvez pas faire ces choses sans les accolades {}.

Paramètres Positionnels

Considérez cet exemple artificiel:

$ chat monecho.sh
echo $1 $2 $3 $4 $5 $6 $7 $8 $9 $10 $11 $12 $13 $14 $15
$ ./myecho.sh Hey diddle diddle, The cat and the fiddle, The cow jumped over the moon.
Hey diddle diddle, The chat0 chat1 chat2 chat3 chat4 chat5

car la shell ne comprend pas $10, $11, etc. Elle traite $10 comme s'il s'agissait de ${1}0. Mais elle comprend ${10}, ${11}, etc., comme mentionné dans la page de manuel "un paramètre positionnel avec plus d'un chiffre".

Mais n'écrivez pas réellement de scripts comme ça; il y a de meilleures façons de traiter les listes d'arguments longues.

Le contenu ci-dessus (ainsi que de nombreuses autres formes de constructions **${**_paramètre…quelque_chose_d'autre_**}**) sont discutés plus en détail dans la page de manuel de la shell, bash(1).

Une Note sur les Guillemets

Notez que vous devriez toujours mettre entre guillemets les variables de shell à moins d'avoir une bonne raison de ne pas le faire, et vous êtes sûr de savoir ce que vous faites. En revanche, bien que les accolades puissent être importantes, elles ne sont pas aussi importantes que les guillemets.

$ nom\_de\_fichier="comptine.txt"
$ ls -ld ${nom\_de\_fichier}
ls: impossible d'accéder à nursery: Aucun fichier ou dossier de ce type
ls: impossible d'accéder à rhyme.txt: Aucun fichier ou dossier de ce type
$ ls -ld "$nom\_de\_fichier"
-rwxr-xr-x  1 Noob Noob   5309 2 juil 11:09 nursery rhyme.txt

Cela s'applique également aux paramètres positionnels (c'est-à-dire, aux arguments de ligne de commande; par exemple, "$1") et également à la substitution de commande:

$ ls -ld $(date "+%B %Y").txt
ls: impossible d'accéder à July: Aucun fichier ou dossier de ce type
ls: impossible d'accéder à 2015.txt: Aucun fichier ou dossier de ce type
$ ls -ld "$(date "+%B %Y").txt"
-rwxr-xr-x  1 Noob Noob    687 2 juil 11:09 July 2015.txt

Voir Les guillemets Bash non échappés sur la substitution de commande pour un bref traité sur l'interaction entre les guillemets et $().

9voto

MariusMatutiae Points 45233

Dans votre exemple, $var et ${var} sont identiques. Cependant, les accolades sont utiles lorsque vous souhaitez étendre la variable dans une chaîne :

$ string=foo
$ echo ${string}bar
  foobar
$ echo $stringbar

$ 

Ainsi, les accolades permettent de substituer la variable afin d'obtenir le nom de la nouvelle variable, elle-même à substituer.

5voto

bytesized Points 153

Je le vois généralement plus couramment dans les chaînes de caractères. Quelque chose comme ceci ne fonctionnera pas :

var="a"
echo "$varRAW_STRING"

Mais ceci fonctionnera :

var="a"
echo "${var}RAW_STRING"

Comme tu l'as dit correctement, $() est utilisé pour exécuter une commande :

dir_contents=$(ls)

Vous pouvez également utiliser des backticks, mais je trouve que le $() est plus polyvalent. Entre autres choses, les backticks ne peuvent pas être (facilement) imbriqués.

date_directory=`ls `date '+%Y-%m-%d'`` # Ne rime à rien
date_directory=$(ls $(date '+%Y-%m-%d')) # Beaucoup mieux

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X