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

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

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

$ echo ${name}
foo

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

Noob
la source
1
${ variable_name }
G-Man dit «Réintègre Monica» le

Réponses:

39

$(command)est la «substitution de commande». Comme vous semblez le comprendre, il exécute le command, capture sa sortie et l'insère dans la ligne de commande qui contient le $(…); par exemple,

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

${parameter}est la «substitution de paramètres». De nombreuses informations peuvent être trouvées dans la page de manuel du shell, bash (1) , sous la rubrique « Expansion des paramètres »:

${parameter}
    La valeur du paramètre est remplacée. Les accolades sont requises lorsque le paramètre est un paramètre positionnel à plusieurs chiffres ou lorsque le 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 de position, voir « Paramètres de position » ci-dessous. Dans son utilisation la plus courante, comme indiqué dans les autres réponses, parameterest 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 ) et de la suivre immédiatement avec une lettre, un chiffre ou un trait de soulignement:$variable_name

$ animal = chat
$ echo $ animaux
                                # Aucune variable telle que «animaux».
$ echo $ {animal} s
chats
$ echo $ animal_food
                                # Aucune variable telle que «animal_food».
$ echo $ {animal} _food
la nourriture pour chat

Vous pouvez également le faire avec des guillemets:

$ echo "$ animal" s
chats

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

$ plural = 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 du 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 du 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 du paramètre lui-même. C'est ce qu'on appelle l' expansion indirecte .     (Exceptions)    Le point d'exclamation doit suivre immédiatement l'accolade gauche pour introduire l'indirection.

Je ne sais pas comment je peux clarifier cela, sauf par exemple:

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

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 chaîne
$ echo $ {animal / at / ow}
vache                              # Substitution

Vous ne pouvez rien faire sans les {}accolades.

Paramètres positionnels

Considérez cet exemple artificiel :

$ cat myecho.sh
écho 1 $ 2 $ 3 $ 4 $ 5 $ 6 $ 7 $ 8 $ 9 $ 10 $ 11 $ 12 $ 13 $ 14 $ 15 $
$ ./myecho.sh Hey diddle diddle, Le chat et le violon, La vache a sauté sur la lune.
Hey diddle diddle, Le chat et le violon, Le Hey0 Hey1 Hey2 Hey3 Hey4 Hey5

parce que la coquille ne comprend pas $10, $11etc. Il traite $10comme si elle était ${1}0. Mais il comprend ${10}, ${11}etc., comme mentionné dans la page de manuel ("un paramètre positionnel à plus d'un chiffre").

Mais n'écrivez pas vraiment des scripts comme ça; il existe de meilleures façons de gérer les longues listes d'arguments.

Ce qui précède (ainsi que de nombreuses autres formes de constructions) sont discutés plus longuement dans la page de manuel du shell, bash (1) .${parameter…something_else}

Une note sur les citations

Notez que vous devez toujours citer les variables du shell, sauf si vous avez une bonne raison de ne pas le faire, et vous êtes sûr de savoir ce que vous faites. En revanche, si les accolades peuvent être importantes, elles ne sont pas aussi importantes que les guillemets.

$ filename = "nursery rhyme.txt"
$ ls -ld $ {filename}
ls: impossible d'accéder à la pépinière: aucun fichier ou répertoire de ce type
ls: impossible d'accéder à rhyme.txt: aucun fichier ou répertoire de ce type
$ ls -ld "$ filename"
-rwxr-xr-x 1 Noob Noob 5309 2 juil 11:09 nursery rhyme.txt

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

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

Voir Bash quotes unescaped on command substitution pour un bref traité sur l'interaction entre les guillemets et $().

G-Man dit «Réintègre Monica»
la source
merci pour le merveilleux exemple. Pouvez-vous élaborer l'utilisation de! dans votre exemple. Je ne comprends pas vraiment comment ça marche.
Noob
@Noob: OK, j'ai expliqué comment utiliser !.
G-Man dit `` Réintègre Monica '' le
Merci. D'une manière ou d'une autre, animal fait en fait référence à la variable chat au lieu de la valeur chat. Pouvez-vous aussi me faire savoir comment / at devient un "c" dans echo $ {animal / at / ow} L'explication de bash par l'homme est en quelque sorte ... je ne sais pas. difficile à comprendre.
Noob
pouvez-vous également élaborer cette phrase - "$ {paramètre} La valeur du paramètre est remplacée." substitué par quoi? si le paramètre est fruit et sa valeur est pomme - fruit = pomme, donc $ {fruit} - pomme est remplacé par ?? n'obtenez pas vraiment le sens ici
Noob
@Noob: " ${!animal}fait référence à la variable $catau lieu de la valeur cat." Oui, c'est exactement le point. "Comment / at devient-il un" c "dans l'écho $ {animal / at / ow}?" Huh? / at ne devient pas "c"; «Chat» devient «vache» lorsque «at» est remplacé par «ow».
G-Man dit `` Réintègre Monica '' le
7

Dans votre exemple, $ var et $ {var} sont identiques. Cependant, 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 offrent un moyen de substituer la variable afin d'obtenir le nom de la nouvelle variable, elle-même à substituer.

MariusMatutiae
la source
4

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

var="a"
echo "$varRAW_STRING"

Mais cela:

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

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

dir_contents=$(ls)

Vous pouvez également utiliser des backticks, mais je trouve le $()plus polyvalent. 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
bytesized
la source
En fait, les apostrophes inverses peuvent être imbriquées: date_directory=`ls \`date '+%Y-%m-%d'\``. Mais c'est terriblement moche; $(…)est beaucoup plus clair et plus facile à utiliser.
G-Man dit `` Réintègre Monica '' le
OK très bien. C'est techniquement possible, mais je ne peux pas imaginer que quiconque le fasse juste à cause de la lisibilité
bytesized
1
Eh bien, `…`était la (seule) syntaxe de substitution de commande pendant des années avant $(…)a été inventé, de sorte que vous n'avez pas besoin d'imaginer quoi que ce soit - les gens l' ont fait.
G-Man dit `` Réintègre Monica '' le
s / jamais le faire / le faire plus /
bytesized