Quelle est la différence entre $ (command) et `command` dans la programmation shell?


258

Pour stocker la sortie d'une commande en tant que variable dans sh / ksh / bash, vous pouvez faire soit

var=$(command)

ou

var=`command`

Quelle est la différence éventuelle entre les deux méthodes?


29

Vous trouverez le problème imbriqué détaillé dans la directive de codage Git: voir ma réponse ci-dessous .
VonC

Réponses:


274

Les backticks / gravmarks ont été déconseillés en faveur de la $()substitution de commandes car ils $()peuvent facilement s'emboîter en eux-mêmes comme dans $(echo foo$(echo bar)). Il existe d'autres différences telles que la façon dont les antislashs sont analysés dans la version backtick / gravemark, etc.

Voir BashFAQ / 082 pour plusieurs raisons de toujours préférer la syntaxe $ (...).

Voir également la spécification POSIX pour des informations détaillées sur les différentes différences.


25
Bon lien, mais ce texte ne déconseille pas les guillemets en faveur de $(...)- il les note simplement comme alternatives.
Norman Gray

24
@NormanGray POSIX peut ne pas dire le mot déconseillé, mais il dit que "the backquoted variety of command substitution is not recommended"ce n'est qu'une façon longue de dire dépréciée à
mon humble avis

11
POSIX n'a ​​pas déprécié les backticks, mais plutôt ajouté $(...)comme méthode alternative. Il n'y a pas de bogue d'implémentation connu avec des backticks, mais il existe de nombreux bogues d'implémentation connus avec $(...) . Ainsi, pour les problèmes de portabilité, il est recommandé d'utiliser des raccourcis pour les appels non imbriqués. $(...)a besoin d'un analyseur récursif mais cela n'a pas été utilisé avec ksh86 qui a introduit la fonctionnalité. Consultez in-ulm.de/~mascheck/various/cmd-subst pour une liste des implémentations correctes. Un shell conforme doit prendre en charge tous les cas sauf le cas D.2.
schily

2
Il y a d'autres choses dans POSIX qui doivent être considérées comme deprecated, par exemple, l'utilisation de waitpid()cela vous empêche de voir les 32 bits complets du exit()paramètre, mais tous les shells à l'exception du Bourne Shell récent utilisent toujours waitpid()au lieu de l' waitid()appel qui est maintenant disponible depuis 26 ans.
schily

Le lien dans la réponse indique qu'il existe des différences entre les backticks et $(), ce qui est expliqué plus en détail dans cette partie de la documentation . Les différences ne concernent pas uniquement l'imbrication.
Un programmeur du

39

Ils se comportent de la même manière. La différence est syntaxique: il est plus facile d'imbriquer $()que ``:

listing=$(ls -l $(cat filenames.txt))

contre.

listing=`ls -l \`cat filenames.txt\``

10
echo $(echo \$abc)n'est pas la même chose que echo `echo \$abc`‍- Des différences existent également pour $(echo \`)et $(echo \\)
Peter.O

Une autre différence est: echo foo `#comment`vs echo foo $(#comment). Le second ne fonctionne pas. (Utilisé pour commenter dans une commande multi-ligne.)
wisbucky

27

Juillet 2014: le commit f25f5e6 (par Elia Pinto ( devzero2000) , avril 2014, Git 2.0) ajoute au problème d'imbrication:

La forme entre guillemets est la méthode traditionnelle de substitution de commandes et est prise en charge par POSIX.
Cependant, toutes les utilisations, sauf les plus simples, se compliquent rapidement.
En particulier, les substitutions de commandes intégrées et / ou l'utilisation de guillemets doubles nécessitent un échappement soigneux avec le caractère barre oblique inverse
.

C'est pourquoi git / Documentation / CodingGuidelines mentionne:

Nous préférons la $( ... )substitution de commandes; contrairement à ``, il niche correctement .
Cela aurait dû être la façon dont Bourne l'a écrit dès le premier jour, mais ce n'est malheureusement pas le cas.

Thiton a commenté :

C'est pourquoi `echo `foo`` ne fonctionnera pas en général en raison de l'ambiguïté inhérente, car chacun ``peut s'ouvrir ou se fermer.
Cela peut fonctionner pour des cas spéciaux en raison de la chance ou de fonctionnalités spéciales.


Mise à jour de janvier 2016: Git 2.8 (mars 2016) supprime complètement les backticks.

Voir commettre ec1b763 , engager 9c10377 , engager c7b793a , engager 80a6b3f , engager 9375dcf , engager e74ef60 , engager 27fe43e , engager 2525c51 , engager becd67f , engager a5c98ac , engager 8c311f9 , engager 57da049 , engager 1d9e86f , engager 78ba28d , engager efa639f , engager 1be2fa0 , commit 38e9476 , commit 8823d2f , commit 32858a0 , commit cd914d8(12 janvier 2016) par Elia Pinto (devzero2000) .
(Fusionné par Junio ​​C Hamano - gitster- dans commit e572fef , 22 janv. 2016)

À partir de Git 2.8, ce $(...)n'est plus tout `...`.


2
$()est également spécifié par POSIX - une citation qui décrit les backticks comme "pris en charge par POSIX" de manière à impliquer que cela leur est unique est trompeur. C'est seulement (époque des années 1970) pré-POSIX Bourne où les backticks sont la seule syntaxe prise en charge.
Charles Duffy

25

Lorsque l'ancienne forme back-tick est utilisée, la barre oblique inverse conserve sa signification littérale, sauf lorsqu'elle est suivie de $, `ou \. Le premier back-tick non précédé d'une barre oblique inverse termine la substitution de commande.

Lors de l'utilisation du plus récent $(command) formulaire, tous les caractères entre parenthèses constituent la commande; aucun n'est traité spécialement.

Les deux formes peuvent être imbriquées, mais la variété back-tick nécessite la forme suivante.

`echo \`foo\`` 

Par opposition à:

$(echo $(foo))

1
Correction mineure, la version backtick et la $()version sont compatibles POSIX.
SiegeX

5

Il y a peu de différence, à l'exception des caractères non échappés que vous pouvez utiliser à l'intérieur de la commande. Vous pouvez même mettre des commandes `...` dans $ (...) (et vice versa) pour une substitution de commande plus compliquée à deux niveaux.

Il existe une interprétation légèrement différente du caractère / opérateur de barre oblique inverse. Entre autres choses, lors de l'imbrication des commandes de substitution `...` , vous devez échapper les caractères internes ` avec \, tandis qu'avec la sous- station $ (), il comprend automatiquement l'imbrication.


0

"Quelle est la différence, le cas échéant, entre les deux méthodes?"

Faites attention à ce comportement:

A="A_VARIABLE"
echo "$(echo "\$A")"
echo "`echo "\$A"`"

Vous obtiendrez ces résultats:

$A
A_VARIABLE

 

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.