Welchen Vorteil hat die Verwendung von $() anstelle von Backticks in Shell-Skripten?

StackOverflow https://stackoverflow.com/questions/9449778

  •  13-11-2019
  •  | 
  •  

Frage

Es gibt zwei Möglichkeiten, die Ausgabe der Befehlszeile zu erfassen bash:

  1. Legacy-Bourne-Shell-Backticks ``:

     var=`command`
    
  2. $() Syntax (die meines Wissens Bash-spezifisch ist oder zumindest von alten Nicht-POSIX-Shells wie der ursprünglichen Bourne nicht unterstützt wird)

     var=$(command)
    

Gibt es einen Vorteil bei der Verwendung der zweiten Syntax im Vergleich zu Backticks?Oder sind die beiden zu 100 % gleichwertig?

War es hilfreich?

Lösung

Das Wichtigste ist die Fähigkeit dazu Nest Sie, Befehle innerhalb von Befehlen, ohne Ihren Verstand zu verlieren und herauszufinden, ob irgendeine Form des Entkommens bei den Backticks funktioniert.

Ein Beispiel, wenn auch etwas gekünstelt:

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

Dadurch erhalten Sie eine Liste aller Dateien im /dir Verzeichnisbaum, der den gleichen Namen wie die früheste datierte Textdatei vom Dezember 2011 hat (A).

Ein anderes Beispiel wäre etwa das Abrufen des Namens (nicht des vollständigen Pfads) des übergeordneten Verzeichnisses:

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

(A) Nun das Spezifisch Der Befehl funktioniert möglicherweise nicht wirklich, ich habe die Funktionalität nicht getestet.Wenn Sie mich also dafür ablehnen, haben Sie die Absicht aus den Augen verloren :-) Es ist lediglich als Veranschaulichung dafür gedacht, wie Sie verschachteln können, und nicht als fehlerfreier, produktionsbereiter Ausschnitt.

Andere Tipps

Angenommen, Sie möchten das entsprechende lib-Verzeichnis finden gcc ist installiert.Du hast eine Wahl:

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

libdir=`dirname \`dirname \\\`which gcc\\\`\``/lib

Das erste ist einfacher als das zweite – verwenden Sie das erste.

Die Backticks (`...`) ist die Legacy-Syntax, die nur von den ältesten nicht POSIX-kompatiblen Bourne-Shells benötigt wird $(...) ist POSIX und wird aus mehreren Gründen bevorzugt:

  • Backslashes (\) Innen-Backticks werden auf nicht offensichtliche Weise gehandhabt:

    $ 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 \\
    
  • Verschachtelte Zitate im Inneren $() ist weitaus bequemer:

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

    anstatt:

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

    oder so etwas schreiben wie:

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

    Weil $() verwendet einen völlig neuen Kontext zum Zitieren

    Dies ist nicht portierbar, da Bourne- und Korn-Shells diese Backslashes erfordern würden, Bash und Dash dagegen nicht.

  • Die Syntax zum Verschachteln von Befehlsersetzungen ist einfacher:

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

    als:

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

    Weil $() erzwingt einen völlig neuen Kontext für Anführungszeichen, sodass jede Befehlsersetzung geschützt ist und einzeln behandelt werden kann, ohne dass besondere Rücksicht auf Anführungszeichen und Escapezeichen genommen werden muss.Bei Verwendung von Backticks wird es ab zwei Levels immer hässlicher.

    Noch ein paar Beispiele:

    echo `echo `ls``      # INCORRECT
    echo `echo \`ls\``    # CORRECT
    echo $(echo $(ls))    # CORRECT
    
  • Es löst ein Problem des inkonsistenten Verhaltens bei der Verwendung von Backquotes:

    • echo '\$x' Ausgänge \$x
    • echo `echo '\$x'` Ausgänge $x
    • echo $(echo '\$x') Ausgänge \$x
  • Die Backticks-Syntax weist historische Einschränkungen hinsichtlich des Inhalts des eingebetteten Befehls auf und kann einige gültige Skripts, die Backquotes enthalten, nicht verarbeiten, während die neueren $() form kann jede Art von gültigem eingebettetem Skript verarbeiten.

    Beispielsweise funktionieren diese ansonsten gültigen eingebetteten Skripte nicht in der linken Spalte, wohl aber in der rechtenIEEE:

    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 ')'
    `                              )
    

Daher ist die Syntax für $-Präfix Befehlsersetzung sollte die bevorzugte Methode sein, da sie visuell klar ist und eine saubere Syntax aufweist (verbessert die Lesbarkeit von Menschen und Maschinen), verschachtelbar und intuitiv ist, ihre innere Analyse separat erfolgt und außerdem konsistenter ist (mit allen anderen Erweiterungen, die von innen analysiert werden). doppelte Anführungszeichen), wobei Backticks die einzige Ausnahme sind und ` Der Charakter lässt sich leicht tarnen, wenn er an ihn angrenzt " Dies macht die Lesbarkeit noch schwieriger, insbesondere bei kleinen oder ungewöhnlichen Schriftarten.

Quelle: Warum ist $(...) bevorzugt gegenüber `...` (Backticks)? bei BashFAQ

Siehe auch:

Von Man 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.

Zusätzlich zu den anderen Antworten,

$(...)

fällt optisch besser auf als

`...`

Backticks sehen zu sehr wie Apostrophe aus;Dies variiert je nach verwendeter Schriftart.

(Und wie ich gerade bemerkt habe, ist es viel schwieriger, Backticks in Inline-Codebeispiele einzugeben.)

$() ermöglicht die Verschachtelung.

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

Ich denke, Backticks lassen das nicht zu.

Es ist der POSIX-Standard, der die definiert $(command) Form der Befehlssubstitution.Die meisten heute verwendeten Shells sind POSIX-kompatibel und unterstützen diese bevorzugte Form gegenüber der veralteten Backtick-Notation.Der Befehlsersetzung Abschnitt (2.6.3) des Shell Language-Dokuments beschreibt dies:

Durch die Befehlsersetzung kann die Ausgabe eines Befehls anstelle des Befehlsnamens selbst ersetzt werden.Die Befehlsersetzung erfolgt, wenn der Befehl wie folgt eingeschlossen wird:

$(Befehl)

oder (rückzitierte Version):

`Befehl`

Die Shell soll die Befehlsersetzung durch Ausführen erweitern Befehlin einer Subshell-Umgebung (siehe Shell-Ausführungsumgebung) und ersetzen die Befehlssubstitution (den Text von Befehl Plus die einschließende "$ ()" oder Backquotes) mit der Standardausgabe des Befehls, wobei Sequenzen von einem oder mehr <newline> Charaktere am Ende der Substitution.Eingebettet <newline> Zeichen vor dem Ende der Ausgabe dürfen nicht entfernt werden;Sie können jedoch als Feldgrenzwerte behandelt und während der Feldaufteilung abhängig vom Wert von IFs und dem Zitat beseitigt werden.Wenn die Ausgabe Null -Bytes enthält, ist das Verhalten nicht spezifiziert.

Im Backquoted-Stil der Befehlsersetzung gilt: <backslash> soll seine wörtliche Bedeutung behalten, außer wenn er folgte:'$' , '`', oder <backslash>.Die Suche nach der passenden Backquote wird durch die erste nicht zahlreiche Backquote erfüllt.Während dieser Suche wird in einem Shell-Kommentar, einem hier-dokument, einer eingebetteten Befehlssubstitution des $ (Befehl) Form oder eine zitierte Zeichenfolge undefinierte Ergebnisse treten auf.Eine einzeln zitierte oder doppelt zitierte Zeichenfolge, die beginnt, aber nicht endet, innerhalb der "`...`"Sequenz erzeugt undefinierte Ergebnisse.

Mit dem $(Befehl) Form sind alle Zeichen, die der offenen Klammung in die übereinstimmende Schließklammern folgen, die Befehl.Dafür kann jedes gültige Shell-Skript verwendet werden Befehl, mit Ausnahme eines Skripts, das ausschließlich aus Umleitungen besteht, die nicht spezifizierte Ergebnisse erzeugen.

Die Ergebnisse der Befehlssubstitution werden nicht zur weiteren Tildeerweiterung, Parameterausdehnung, Befehlssubstitution oder arithmetischer Expansion verarbeitet.Wenn eine Befehlssubstitution in doppelten Zitaten auftritt, dürfen die Feldaufteilung und die Pathname-Expansion nicht mit den Ergebnissen der Substitution durchgeführt werden.

Befehlsersetzungen können verschachtelt sein.Um die Verschachtelung innerhalb der Backquoted -Version anzugeben, muss der Antrag den inneren Rückquoten mit vorangehen <backslash> Figuren;Zum Beispiel:

\`Befehl\`

Die Syntax der Shell-Befehlssprache weist eine Mehrdeutigkeit für Erweiterungen auf, die mit „“ beginnen.$((", die eine arithmetische Expansion oder einen Befehlssubstitution einführen kann, der mit einer Unterschale beginnt.Die arithmetische Entwicklung hat Vorrang;Das heißt, die Hülle muss zunächst bestimmen, ob sie die Ausdehnung als arithmetische Expansion analysieren kann, und die Ausdehnung nur als Befehlssubstitution analysieren, wenn sie feststellt, dass sie die Expansion nicht als arithmetische Expansion analysieren kann.Die Shell muss bei dieser Bestimmung keine verschachtelten Erweiterungen auswerten.Wenn es auf das Ende der Eingabe trifft, ohne bereits festzustellen, dass es die Expansion nicht als arithmetische Expansion analysieren kann, behandelt die Hülle die Ausdehnung als unvollständige arithmetische Expansion und meldet einen Syntaxfehler.Eine konforme Anwendung muss sicherstellen, dass sie die „$(" Und '('In zwei Token (dh sie trennen sie mit Weißraum) in einer Befehlssubstitution, die mit einer Unterschale beginnt.Beispielsweise könnte eine Befehlsersetzung, die eine einzelne Subshell enthält, wie folgt geschrieben werden:

$( (Befehl) )

Dies ist eine alte Frage, aber ich habe ein vollkommen gültiges Beispiel dafür gefunden $(...) über `...`.

Ich habe einen Remote-Desktop für Windows verwendet, auf dem Cygwin ausgeführt wurde, und wollte das Ergebnis eines Befehls durchlaufen.Leider konnte das Backtick-Zeichen nicht eingegeben werden, entweder aufgrund der Remote-Desktop-Sache oder aufgrund von Cygwin selbst.

Es ist vernünftig anzunehmen, dass ein Dollarzeichen und Klammern in solch seltsamen Konfigurationen einfacher einzugeben sind.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top