web-dev-qa-db-fra.com

Quel est l'avantage d'utiliser $ () plutôt que des backticks dans les scripts Shell?

Il existe deux manières de capturer le résultat de la ligne de commande dans bash:

  1. Backticks Legacy Bourne Shell ``:

     var=`command`
    
  2. $() syntaxe (qui, autant que je sache, est spécifique à Bash, ou du moins n'est pas supportée par les anciens shells non-POSIX comme Bourne d'origine)

     var=$(command)
    

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

142
DVK

Le principal est la capacité de imbriquer eux, commandes au sein de commandes, sans perdre votre sens de la raison en essayant de déterminer si une forme d’évasion fonctionnera sur les backticks.

Un exemple, bien que 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 dans le /dir arborescence de répertoires portant le même nom que le fichier texte le plus ancien datant de décembre 2011 (une).

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

(une) Maintenant que la commande spécifique risque de ne pas fonctionner, je n'ai pas testé la fonctionnalité. Donc, si vous me refusez, vous avez perdu de vue l'intention :-) Cela signifie simplement à titre d'illustration sur la façon dont vous pouvez imbriquer, et non comme un extrait prêt à être utilisé sans production.

134
paxdiablo

Supposons que vous souhaitiez trouver le répertoire lib correspondant à l'emplacement où gcc est installé. 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.

50
Jonathan Leffler

Les backticks (`...`) Sont la syntaxe héritée requise par le très ancien bourne-shell non compatible POSIX et $(...) est POSIX et davantage préféré pour plusieurs raisons:

  • Les barres obliques inversées (\) 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 \\
    
  • La citation imbriquée dans $() est beaucoup plus pratique:

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

    au lieu de:

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

    ou écrire quelque chose comme:

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

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

    qui n'est pas portable, car les obus Bourne et Korn auraient besoin de ces barres obliques inverses, contrairement à Bash et Dash.

  • La syntaxe de substitution des commandes est plus simple:

    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 pour la citation et l'échappement. Lors de l'utilisation de backticks, il devient plus laid 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
    
  • Cela résout un problème de comportement incohérent lors de l'utilisation de citations arrières:

    • echo '\$x' Génère \$x
    • echo `echo '\$x'` Génère $x
    • echo $(echo '\$x') génère \$x
  • La syntaxe Backticks a des restrictions historiques sur le contenu de la commande incorporée et ne peut pas gérer certains scripts valides incluant des guillemets, tandis que la nouvelle forme $() peut traiter tout type de script incorporé valide.

    Par exemple, ces scripts incorporés par ailleurs valides 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 de $ - avec le préfixe substitution de commande devrait être la méthode préférée, car elle est claire visuellement avec une syntaxe propre (améliore la lisibilité humaine et machine), elle est imbriquée et intuitive. l'analyse interne est distincte et plus cohérente (avec toutes les autres extensions analysées à partir de guillemets doubles), les backticks étant la seule exception et le caractère ` se camouflant facilement lorsqu'il est adjacent à " rendant la lecture encore plus difficile, surtout avec des polices de petite taille ou inhabituelles.

Source: Pourquoi $(...) est-elle préférée à `...` (Morsures)? chez BashFAQ

Voir également:

26
kenorb

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.
21
dgw

En plus des autres réponses,

$(...)

se distingue visuellement mieux que

`...`

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

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

9
Keith Thompson

$() permet l'imbrication.

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

Je pense que les backticks ne le permettent pas.

6
Shiplu Mokaddim

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 sous cygwin et je voulais parcourir le résultat d'une commande. Malheureusement, il était impossible de saisir le caractère de backtick, que ce soit par le biais du bureau à distance ou de cygwin lui-même.

Il est raisonnable de supposer qu'un signe dollar et des parenthèses seront plus faciles à saisir dans des configurations aussi étranges.

3
Piotr Zierhoffer

C'est le standard POSIX qui définit la forme de substitution de commande $(command). La plupart des shells utilisés actuellement sont compatibles POSIX et supportent cette forme préférée par rapport à la notation archaïque backtick. La section substitution de commande (2.6.3) du document de langage shell décrit ceci:

La substitution de commande permet de substituer 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 enfermée comme suit:

$(command)

ou (version inversée):

`command`

Le shell doit étendre 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 le "$ ()" ou les guillemets arrières) avec la sortie standard de la commande, en supprimant les séquences d'un ou plusieurs <newline> Caractères à la fin de la substitution. Les caractères <newline> 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 scission de champ, en fonction de la valeur de 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 inversé, <backslash> Conserve son sens littéral, sauf lorsqu'il est suivi de: '$', '`' Ou <backslash> . La recherche de la citation correspondante doit être satisfaite par la première citation non échappée non échappée; au cours de cette recherche, si un commentaire non échappé est rencontré dans un commentaire Shell, un document here, une substitution de commande incorporée de la commande $ ( ((=== ==)) ) forme, ou une chaîne entre guillemets, des résultats non définis se produisent. Une chaîne entre guillemets simples ou guillemets doubles qui commence sans se terminer dans la séquence "`...`" Produit des résultats non définis.

Avec la forme $ ( 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 , à l'exception d'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 un développement ultérieur des tilde, des paramètres, de la substitution de commandes ou du développement arithmétique. Si une substitution de commande se produit entre guillemets, le fractionnement des champs et le développement du nom de chemin ne doivent pas être effectués sur les résultats de la substitution.

La substitution de commande peut être imbriquée. Pour spécifier une imbrication dans la version entre guillemets, l'application doit précéder les guillemets intérieurs avec des caractères <backslash>; par exemple:

\`command\`

La syntaxe du langage de commande Shell présente une ambiguïté pour les extensions commençant par "$((", Ce qui peut introduire une extension arithmétique ou une substitution de commande commençant par un sous-shell. L'expansion arithmétique a la priorité; En d'autres termes, le shell doit d'abord déterminer s'il peut analyser le développement en tant que développement arithmétique et n'analysera le développement en tant que substitution de commande que s'il est déterminé qu'il ne peut pas analyser le développement en tant que développement arithmétique. Le shell n’a pas besoin d’évaluer les extensions imbriquées lors de cette détermination. S'il rencontre la fin de l'entrée sans avoir déjà déterminé qu'il ne peut pas analyser le développement comme un développement arithmétique, le shell considérera le développement comme un développement arithmétique incomplet et signalera une erreur de syntaxe. Une application conforme doit veiller à séparer les "$(" Et "(" En deux jetons (en les séparant par un espace) dans une substitution de commande commençant par un sous-shell. Par exemple, une substitution de commande contenant un seul sous-shell pourrait être écrite comme suit:

$( (command) )

2
JRFerguson