web-dev-qa-db-fra.com

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

$ echo $(date)
Thu Jul 2 16:33:11 SGT 2015
$ echo ${date}

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

$ echo ${name}
foo

On dirait que $ {variable} est identique à $ variable. tandis que $ () doit exécuter une commande. Pourquoi utiliser $ {} alors?

23
Noob

$(command) est "substitution de commande". Comme vous semblez le comprendre, il exécute la command, en capture le résultat 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 Jul  2 11:09 July.txt

${parameter} est "substitution de paramètre". Vous trouverez de nombreuses informations dans la page de manuel de Shell, bash (1) , sous la rubrique " Parameter Expansion ”rubrique:

${parameter}
    La valeur de paramètreest substitué. Les accolades sont nécessaires lorsque paramètreest un paramètre de position avec plus d'un chiffre, ou lorsque paramètreest suivi d'un caractère qui ne doit pas être interprété comme faisant partie de son nom.

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

$ animal = chat 
 $ echo $ animaux 
 # Aucune variable telle que “Animaux”. 
 $ Echo $ {animal} s 
 Chats 
 $ Echo $ aliments_animaux 
 # Aucune variable telle que “Animal_food”. 
 $ Echo $ {animal} _food 
 Chat_food

Vous pouvez également le faire avec des guillemets:

$ echo "$ animal" s 
 chats

Ou, comme exercice d’options, vous pouvez utiliser une deuxième variable:

$ pluriel = s 
 $ echo $ animal $ pluriel 
 chats

Mais ceci 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 variable est introduit. Bash utilise la valeur de la variable formée à partir du reste de paramètre comme le 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. Ceci est connu comme expansion indirecte(exceptions)Le point d'exclamation doit immédiatement suivre l'accolade de gauche afin d'introduire l'indirection.

Je ne sais pas comment rendre cela plus clair si ce n’est par exemple:

$ animal = chat 
 $ echo $ animal 
 chat 
 $ cat = tabby 
 $ echo $ cat 
 tabby 
 $ echo $ {! animal} 
 tabby # Si $ animal est "chat", puis $ {! animal} est $ chat, c'est à dire., "tigré"

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

$ animal = chat 
 $ echo $ {# animal} 
 3 # Longueur de chaine
 $ echo $ {animal/at/ow} 
 vache # Substitution

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

Paramètres de position

Considérons cet exemple artificiel :

$ cat myecho.sh 
 echo $ 1 $ 2 $ 3 $ 4 $ 5 $ 6 $ 7 $ 8 $ 9 $ 10 $ 11 $ 12 $ 13 $ 14 $ 15 $ 
 $ ./myecho.sh Au-dessus de la lune. 
 Hey diddle diddle, Le chat et le violon, Le Hey0 Hey1 Hey2 Hey3 Hey4 Hey4

car le shell ne comprend pas $10, $11, etc. Il traite $10 comme s'il s'agissait de ${1}0. Cependant, il comprend ${10}, ${11}, etc., comme indiqué dans la page de manuel ("paramètre de position comportant plus d'un chiffre").

Mais n’écrivez pas réellement de tels scripts; il existe de meilleurs moyens de gérer de longues listes d'arguments.

Les exemples ci-dessus (ainsi que de nombreuses autres formes de constructions ${parameter…something_else}) sont décrits plus en détail dans la page de manuel de Shell, bash (1) .

Note sur les citations

Notez que vous devez toujours citer les variables Shell à moins d’avoir une bonne raison de ne pas le faire et que vous êtes sûr de savoir ce que vous faites. En revanche, les accolades peuvent être importantes, mais pas autant que les guillemets.

$ filename = "nursery rhyme.txt" 
 $ ls -ld $ {nom_fichier} 
 ls: impossible d'accéder à nursery: pas de fichier ou répertoire de ce type 
 ls: impossible d'accéder à rhyme.txt : Aucun fichier ou répertoire de ce type 
 $ Ls -ld "$ nom_fichier" 
 - rwxr-xr-x 1 Noob Noob 5309 2 juillet 11:09 nursery rhyme.txt

Cela s’applique également aux paramètres de position (par exemple, les arguments de ligne de commande; par exemple, "$1"), ainsi qu’à la substitution de commande:

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

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

31
G-Man

Dans votre exemple, $ var et $ {var} sont identiques. Toutefois, les accolades sont utiles lorsque vous souhaitez développer 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 à remplacer.

6
MariusMatutiae

Je le vois généralement plus communément dans les chaînes. Quelque chose comme ça ne fonctionnera pas:

var="a"
echo "$varRAW_STRING"

Mais cela va:

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

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

dir_contents=$(ls)

Vous pouvez également utiliser des backticks, mais je trouve la $() plus polyvalente. D'une part, les backticks ne peuvent pas être (facilement) imbriqués.

date_directory=`ls `date '+%Y-%m-%d'`` # Makes no sense
date_directory=$(ls $(date '+%Y-%m-%d')) # Much better
3
bytesized