Quel est l’avantage d’utiliser $ () au lieu des backticks dans les scripts shell?

Il existe deux manières de capturer la sortie de la ligne de commande dans bash :

  1. Backticks du shell Bourne hérité `` :

      var=`command` 
  2. $() syntaxe (qui pour autant que je sache est spécifique à Bash)

      var=$(command) 

Y a-t-il un avantage à utiliser la deuxième syntaxe par rapport aux backticks? Ou les deux sont-ils entièrement équivalents à 100%?

Le principal est la possibilité de les imbriquer , les commandes dans les commandes, sans perdre votre santé mentale en essayant de déterminer si une forme de fuite fonctionnera sur les backticks.

Un exemple, quoique quelque peu artificiel:

 deps=$(find /dir -name $(ls -1tr 201112[0-9][0-9]*.txt | tail -1l) -print) 

qui vous donnera une liste de tous les fichiers de l’arborescence de répertoires /dir qui ont le même nom que le fichier texte daté le plus ancien de décembre 2011 (a) .

Un autre exemple serait quelque chose comme obtenir le nom (pas le chemin complet) du répertoire parent:

 pax> cd /home/pax/xyzzy/plugh pax> parent=$(basename $(dirname $PWD)) pax> echo $parent xyzzy 

(a) Maintenant que cette commande spécifique ne fonctionne pas, je n’ai pas testé la fonctionnalité. Donc, si vous me votez pour cela, vous avez perdu de vue l’intention 🙂 Cela signifie juste comme une illustration de la façon dont vous pouvez imbriquer, pas comme un extrait de production prêt sans bug.

Supposons que vous souhaitiez trouver le répertoire lib correspondant à l’emplacement d’installation de gcc . Tu as le choix:

 libdir=$(dirname $(dirname $(which gcc)))/lib libdir=`dirname \`dirname \\\`which gcc\\\`\``/lib 

Le premier est plus facile que le second – utilisez le premier.

De l’homme bash:

  $(command) or `command` Bash performs the expansion by executing command and replacing the com- mand substitution with the standard output of the command, with any trailing newlines deleted. Embedded newlines are not deleted, but they may be removed during word splitting. The command substitution $(cat file) can be replaced by the equivalent but faster $(< file). When the old-style backquote form of substitution is used, backslash retains its literal meaning except when followed by $, `, or \. The first backquote not preceded by a backslash terminates the command sub- stitution. When using the $(command) form, all characters between the parentheses make up the command; none are treated specially. 

Le backticks ( `...` ) est la syntaxe héritée requirejse par le plus ancien des bourne-shells non compatibles avec POSIX et $(...) est POSIX et plus préféré pour plusieurs raisons:

  • Les barres obliques inverses ( \ ) à l’intérieur des backticks sont traitées de manière non évidente:

     $ echo "`echo \\a`" "$(echo \\a)" a \a $ echo "`echo \\\\a`" "$(echo \\\\a)" \a \\a # Note that this is true for *single quotes* too! $ foo=`echo '\\'`; bar=$(echo '\\'); echo "foo is $foo, bar is $bar" foo is \, bar is \\ 
  • Les guillemets nesteds dans $() sont beaucoup plus pratiques:

     echo "x is $(sed ... <<<"$y")" 

    au lieu de:

     echo "x is `sed ... <<<\"$y\"`" 

    ou écrire quelque chose comme:

     IPs_inna_ssortingng=`awk "/\`cat /etc/myname\`/"'{print $1}' /etc/hosts` 

    parce que $() utilise un contexte entièrement nouveau pour citer

    ce qui n'est pas portable car les shells Bourne et Korn nécessiteraient ces antislash, alors que Bash et Dash ne le font pas.

  • La syntaxe de substitution des commandes d'imbrication est plus facile:

     x=$(grep "$(dirname "$path")" file) 

    que:

     x=`grep "\`dirname \"$path\"\`" file` 

    Parce que $() applique un contexte entièrement nouveau pour la citation, chaque substitution de commande est protégée et peut être traitée seule sans souci particulier de la citation et de la fuite. Lors de l'utilisation de backticks, il devient plus moche et plus laid après deux niveaux et plus.

    Quelques exemples supplémentaires:

     echo `echo `ls`` # INCORRECT echo `echo \`ls\`` # CORRECT echo $(echo $(ls)) # CORRECT 
  • Il résout un problème de comportement incohérent lors de l'utilisation de backquotes:

    • echo '\$x' sorties \$x
    • echo `echo '\$x'` sorties $x
    • echo $(echo '\$x') sorties \$x
  • La syntaxe Backticks a des ressortingctions historiques sur le contenu de la commande incorporée et ne peut pas gérer certains scripts valides incluant des backquotes, tandis que le nouveau formulaire $() peut traiter tout type de script incorporé valide.

    Par exemple, ces scripts incorporés valides par ailleurs ne fonctionnent pas dans la colonne de gauche, mais fonctionnent à droite IEEE :

     echo ` echo $( cat <<\eof cat <<\eof a here-doc with ` a here-doc with ) eof eof ` ) echo ` echo $( echo abc # a comment with ` echo abc # a comment with ) ` ) echo ` echo $( echo '`' echo ')' ` ) 

Par conséquent, la syntaxe pour la substitution de commande $ -prefixed devrait être la méthode préférée, car elle est visuellement claire avec une syntaxe propre (améliore la lisibilité de l'homme et de la machine), est nestede et intuitive, son parsing interne est séparée et plus cohérente ( avec toutes les autres extensions qui sont analysées à partir des guillemets doubles) où les backticks sont la seule exception et ` personnage est facilement camouflé lorsqu'il est adjacent à " ce qui le rend encore plus difficile à lire, en particulier avec des fonts petites ou inhabituelles.

Source: Pourquoi $(...) préféré à `...` (backticks)? chez BashFAQ

Voir également:

  • Section standard POSIX "2.6.3 Substitution de commandes"
  • Raison d'être de POSIX pour inclure la syntaxe $ ()
  • Substitution de commandes
  • bash-hackers: substitution de commandes

En plus des autres réponses,

 $(...) 

se distingue visuellement mieux que

 `...` 

Les backticks ressemblent trop à des apostrophes; cela varie en fonction de la police que vous utilisez.

(Et, comme je viens de le remarquer, les backticks sont beaucoup plus difficiles à saisir dans les exemples de code en ligne.)

$() permet l’imbrication.

 out=$(echo today is $(date)) 

Je pense que les backticks ne le permettent pas.

C’est la norme POSIX qui définit la forme de substitution de commandes $(command) . La plupart des shells utilisés aujourd’hui sont conformes à POSIX et prennent en charge cette forme préférée sur la notation archaïque du backtick. La section de substitution de commande (2.6.3) du document Shell Language décrit ceci:

La substitution de commandes permet de remplacer la sortie d’une commande à la place du nom de la commande elle-même. La substitution de commande doit se produire lorsque la commande est entourée comme suit:

$( command )

ou (version rétroactive):

` command `

Le shell développera la substitution de commande en exécutant la commande dans un environnement de sous-shell (voir Environnement d’exécution de shell ) et en remplaçant la substitution de commande (le texte de la commande plus “$ ()” ou les backquotes) avec la sortie standard de la commande séquences d’un ou plusieurs caractères à la fin de la substitution. Les caractères incorporés avant la fin de la sortie ne doivent pas être supprimés; cependant, ils peuvent être traités comme des délimiteurs de champ et éliminés lors de la division de champ, en fonction de la valeur de l’IFS et de la citation en vigueur. Si la sortie contient des octets nuls, le comportement n’est pas spécifié.

Dans le style de substitution de commande, conservera sa signification littérale, sauf si elle est suivie de: ‘ $ ‘, ‘ ` ‘ ou . La recherche de la backquote correspondante doit être satisfaite par le premier backquote non cité non échappé; Au cours de cette recherche, si un backquote non échappé est rencontré dans un commentaire de shell, un document ici, une substitution de commande incorporée du formulaire $ ( commande ) ou une chaîne entre guillemets, des résultats non définis apparaissent. Une chaîne entre guillemets simples ou entre guillemets qui commence, mais ne s’arrête pas, dans la séquence ” `...` ” produit des résultats indéfinis.

Avec le formulaire $ ( commande ), tous les caractères suivant la parenthèse ouverte à la parenthèse fermante correspondante constituent la commande . Tout script shell valide peut être utilisé pour la commande , sauf un script composé uniquement de redirections qui produit des résultats non spécifiés.

Les résultats de la substitution de commande ne doivent pas être traités pour une extension de tilde, une extension de paramètre, une substitution de commande ou une expansion arithmétique. Si une substitution de commande intervient à l’intérieur des guillemets, le fractionnement des champs et l’extension des chemins ne doivent pas être effectués sur les résultats de la substitution.

La substitution de commande peut être nestede. Pour spécifier l’imbrication dans la version cotée, l’application doit précéder les guillemets intérieurs avec des caractères ; par exemple:

\` command \`

La syntaxe du langage de commande shell a une ambiguïté pour les expansions commençant par ” $(( “, qui peut introduire une expansion arithmétique ou une substitution de commande commençant par un sous-shell. L’expansion arithmétique a la priorité, c’est-à-dire que Il peut parsingr l’expansion sous la forme d’une extension arithmétique et parsingr l’parsing uniquement en tant que substitution de commande si elle détermine qu’elle ne peut pas parsingr l’expansion comme une extension arithmétique. Le shell n’a pas besoin d’évaluer les extensions nestedes lors de cette détermination. de l’entrée sans avoir déjà déterminé qu’elle ne peut pas parsingr l’expansion sous forme d’expansion arithmétique, le shell traitera l’expansion comme une extension arithmétique incomplète et signalera une erreur de syntaxe. Une application conforme devra s’assurer qu’elle sépare le ” $( ” et ” ( ‘en deux jetons (c’est-à-dire les séparer avec un espace blanc) dans une substitution de commande qui commence par un sous-shell. Par exemple, une comm et la substitution contenant un seul sous-shell pourrait être écrite comme suit:

$( ( command ) )

C’est une question héritée, mais j’ai trouvé un exemple parfaitement valide de $(...) sur `...` .

J’utilisais un poste de travail distant pour Windows exécutant cygwin et je voulais parcourir un résultat d’une commande. Malheureusement, le caractère backtick était impossible à entrer, que ce soit à cause du bureau distant ou de cygwin lui-même.

Il est sain de supposer qu’un signe dollar et des parenthèses seront plus faciles à taper dans de telles configurations étranges.