tl; dr
Une semelle stuff
fonctionnerait très probablement pour vous.
Réponse complète
Ce qui se produit
Lorsque vous exécutez foo $(stuff)
, voici ce qui se passe:
stuff
court;
- sa sortie (stdout), au lieu d'être imprimée, remplace
$(stuff)
dans l'invocation de foo
;
foo
s'exécute ensuite , ses arguments de ligne de commande dépendent évidemment de ce qui stuff
est retourné.
Ce $(…)
mécanisme est appelé "substitution de commande". Dans votre cas, la commande principale est celle echo
qui affiche essentiellement ses arguments de ligne de commande sur stdout. Donc, tout ce qui stuff
essaie d'imprimer sur stdout est capturé, passé echo
et imprimé sur stdout par echo
.
Si vous souhaitez que la sortie de stuff
soit imprimée sur stdout, exécutez simplement la semelle stuff
.
La `…`
syntaxe sert le même but que $(…)
(sous le même nom: "substitution de commande"), il y a cependant peu de différences, vous ne pouvez donc pas les échanger aveuglément. Voir cette FAQ et cette question .
Dois-je éviter echo $(stuff)
quoi qu'il arrive?
Il y a une raison que vous voudrez peut-être utiliser echo $(stuff)
si vous savez ce que vous faites. Pour la même raison, vous devriez éviter echo $(stuff)
si vous ne savez pas vraiment ce que vous faites.
Le point est stuff
et echo $(stuff)
n'est pas exactement équivalent. Ce dernier signifie appeler l'opérateur split + glob sur la sortie de stuff
avec la valeur par défaut de $IFS
. Le double guillemet de la substitution de commande empêche cela. Le simple guillemet de la substitution de commande fait qu'il ne s'agit plus d'une substitution de commande.
Pour observer cela lorsqu'il s'agit de fractionner, exécutez ces commandes:
echo "a b"
echo $(echo "a b")
echo "$(echo "a b")" # the shell is smart enough to identify the inner and outer quotes
echo '$(echo "a b")'
Et pour le globbing:
echo "/*"
echo $(echo "/*")
echo "$(echo "/*")" # the shell is smart enough to identify the inner and outer quotes
echo '$(echo "/*")'
Comme vous pouvez le voir echo "$(stuff)"
est équivalent (-ish *) à stuff
. Vous pouvez l'utiliser, mais à quoi bon compliquer les choses de cette façon?
D'un autre côté, si vous souhaitez que la sortie de stuff
subisse un fractionnement + globalisation, vous pouvez trouver echo $(stuff)
utile. Mais cela doit être votre décision consciente.
Il existe des commandes générant une sortie qui doivent être évaluées (ce qui inclut le fractionnement, la globalisation et plus encore) et exécutées par le shell, c'est donc eval "$(stuff)"
une possibilité (voir cette réponse ). Je n'ai jamais vu une commande qui a besoin de sa sortie pour subir un fractionnement + globalisation supplémentaire avant d'être imprimée . L'utilisation délibérée echo $(stuff)
semble très rare.
Et alors var=$(stuff); echo "$var"
?
Bon point. Cet extrait:
var=$(stuff)
echo "$var"
devrait être équivalent à echo "$(stuff)"
équivalent (-ish *) à stuff
. Si c'est tout le code, lancez-le à la stuff
place.
Si, toutefois, vous devez utiliser la sortie de stuff
plusieurs fois, cette approche
var=$(stuff)
foo "$var"
bar "$var"
est généralement mieux que
foo "$(stuff)"
bar "$(stuff)"
Même si foo
c'est le cas echo
et que vous obtenez echo "$var"
votre code, il peut être préférable de le conserver de cette façon. Choses à considérer:
- Avec des
var=$(stuff)
stuff
courses une fois; même si la commande est rapide, éviter de calculer deux fois la même sortie est la bonne chose. Ou peut-êtrestuff
a des effets autres que l'écriture sur stdout (par exemple la création d'un fichier temporaire, le démarrage d'un service, le démarrage d'une machine virtuelle, la notification d'un serveur distant), de sorte que vous ne voulez pas l'exécuter plusieurs fois.
- Si
stuff
génère une sortie temporelle ou quelque peu aléatoire, vous pouvez obtenir des résultats incohérents à partir de foo "$(stuff)"
et bar "$(stuff)"
. Après que var=$(stuff)
la valeur de $var
est fixée, vous pouvez être sûr foo "$var"
et bar "$var"
obtenir un argument de ligne de commande identique.
Dans certains cas, au lieu de foo "$var"
vous pouvez vouloir (besoin) d'utiliser foo $var
, en particulier si stuff
génère plusieurs arguments pour foo
(une variable de tableau peut être meilleure si votre shell le prend en charge). Encore une fois, sachez ce que vous faites. En ce qui concerne echo
la différence entre echo $var
et echo "$var"
est le même qu'entre echo $(stuff)
et echo "$(stuff)"
.
* Équivalent ( -ish )?
J'ai dit echo "$(stuff)"
est équivalent (-ish) à stuff
. Il y a au moins deux problèmes qui ne le rendent pas exactement équivalent:
$(stuff)
s'exécute stuff
dans un sous-shell, il est donc préférable de dire echo "$(stuff)"
est équivalent (-ish) à (stuff)
. Les commandes qui affectent le shell dans lequel elles s'exécutent, si elles sont dans un sous-shell, n'affectent pas le shell principal.
Dans cet exemple, stuff
voici a=1; echo "$a"
:
a=0
echo "$(a=1; echo "$a")" # echo "$(stuff)"
echo "$a"
Comparez-le avec
a=0
a=1; echo "$a" # stuff
echo "$a"
et avec
a=0
(a=1; echo "$a") # (stuff)
echo "$a"
Un autre exemple, commencez par stuff
être cd /; pwd
:
cd /bin
echo "$(cd /; pwd)" # echo "$(stuff)"
pwd
et test stuff
et (stuff)
versions.
echo
n'est pas un bon outil pour afficher des données non contrôlées . Ce dont echo "$var"
nous parlions aurait dû être printf '%s\n' "$var"
. Mais comme la question mentionne echo
et que la solution la plus probable est de ne pas l'utiliser echo
en premier lieu, j'ai décidé de ne pas introduire printf
jusqu'à présent.
stuff
ou (stuff)
entrelacera les sorties stdout et stderr, tandis que echo $(stuff)
toutes les sorties stderr de stuff
(qui s'exécute en premier) seront imprimées , et alors seulement la sortie stdout digérée par echo
(qui s'exécutera en dernier).
$(…)
supprime toute nouvelle ligne de fin, puis l' echo
ajoute en arrière. echo "$(printf %s 'a')" | xxd
Donne donc une sortie différente de printf %s 'a' | xxd
.
Certaines commandes ( ls
par exemple) fonctionnent différemment selon que la sortie standard est une console ou non; il ls | cat
n'en va pas de même ls
. De même echo $(ls)
fonctionnera différemment que ls
.
Mis à ls
part, dans un cas général, si vous devez forcer cet autre comportement, stuff | cat
c'est mieux que echo $(ls)
ou echo "$(ls)"
parce qu'il ne déclenche pas tous les autres problèmes mentionnés ici.
Peut-être un statut de sortie différent (mentionné pour l'exhaustivité de cette réponse wiki; pour plus de détails, voir une autre réponse qui mérite le crédit).