Was ist der Unterschied zwischen $ (Befehl) und `Befehl` bei der Shell-Programmierung?

258

Sie können beides tun, um die Ausgabe eines Befehls als Variable in sh / ksh / bash zu speichern

var=$(command)

oder

var=`command`

Was ist der Unterschied zwischen den beiden Methoden?

hhafez
quelle
29
Bitte siehe BashFAQ / 082 .
Bis auf weiteres angehalten.
Das verschachtelte Problem finden Sie in der Git-Codierungsrichtlinie: siehe meine Antwort unten .
VonC

Antworten:

274

Die Backticks / Gravemarks wurden zugunsten der $()Befehlsersetzung verworfen, da $()sie wie in sich leicht in sich selbst verschachteln können $(echo foo$(echo bar)). Es gibt andere Unterschiede, z. B. wie Backslashes in der Backtick- / Gravemark-Version analysiert werden usw.

Siehe BashFAQ / 082 aus mehreren Gründen, um immer die Syntax $ (...) zu bevorzugen.

Ausführliche Informationen zu den verschiedenen Unterschieden finden Sie auch in der POSIX- Spezifikation.

SiegeX
quelle
25
Guter Link, aber dieser Text veraltet Backquotes nicht zugunsten von $(...)- er vermerkt sie nur als Alternativen.
Norman Gray
24
@NormanGray POSIX sagt möglicherweise nicht das Wort veraltet, aber es sagt, "the backquoted variety of command substitution is not recommended"was nur eine langwierige Art zu sagen veraltet ist IMHO
SiegeX
11
POSIX hat Backticks nicht verworfen, sondern $(...)als alternative Methode hinzugefügt . Es ist kein Implementierungsfehler mit Backticks bekannt, aber es sind viele Implementierungsfehler bekannt $(...) . Aus Gründen der Portabilität wird daher empfohlen, Backticks für nicht verschachtelte Anrufe zu verwenden. $(...)benötigt einen rekursiven Parser, der jedoch nicht mit ksh86 verwendet wurde, mit dem die Funktion eingeführt wurde. Unter inulm.de/~mascheck/various/cmd-subst finden Sie eine Liste der korrekten Implementierungen. Eine konforme Shell muss alle Fälle außer Fall D.2 unterstützen.
schily
2
Es gibt andere Dinge in POSIX, die gesehen werden müssen deprecated, z. B. die Verwendung waitpid()davon verhindert, dass Sie die vollen 32 Bits des exit()Parameters sehen können, aber alle Shells außer der aktuellen Bourne Shell werden weiterhin waitpid()anstelle des waitid()Aufrufs verwendet, der seitdem verfügbar ist 26 Jahre.
schily
Der Link in der Antwort weist darauf hin, dass es einige Unterschiede zwischen den Backticks und gibt $(), was in diesem Teil der Dokumentation näher erläutert wird . Die Unterschiede betreffen nicht nur das Verschachteln.
Einige Programmierer Typ
39

Sie verhalten sich gleich. Der Unterschied ist syntaktisch: Es ist einfacher zu verschachteln $()als ``:

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

vs.

listing=`ls -l \`cat filenames.txt\``
John Kugelman
quelle
10
echo $(echo \$abc)ist nicht dasselbe wie echo `echo \$abc`‍- Unterschiede bestehen auch für $(echo \`)und $(echo \\)
Peter.O
Ein weiterer Unterschied ist: echo foo `#comment`vs echo foo $(#comment). Der zweite funktioniert nicht. (Wird zum Kommentieren in einem mehrzeiligen Befehl verwendet.)
wisbucky
27

Juli 2014: Das Commit f25f5e6 (von Elia Pinto ( devzero2000) , April 2014, Git 2.0) ergänzt das Verschachtelungsproblem:

Das zurück zitierte Formular ist die traditionelle Methode zur Befehlssubstitution und wird von POSIX unterstützt.
Alle bis auf die einfachsten Anwendungen werden jedoch schnell kompliziert.
Insbesondere eingebettete Befehlsersetzungen und / oder die Verwendung von doppelten Anführungszeichen erfordern ein vorsichtiges Escapezeichen mit dem Backslash-Zeichen
.

Aus diesem Grund wird in den Richtlinien git / Documentation / CodingGuidelines Folgendes erwähnt:

Wir bevorzugen die $( ... )Befehlsersetzung; im Gegensatz zu `` nistet es richtig .
Es hätte so sein sollen, wie Bourne es vom ersten Tag an geschrieben hat, ist es aber leider nicht.

Thiton kommentierte :

Das ist der Grund, warum dies `echo `foo`` aufgrund der inhärenten Mehrdeutigkeit im Allgemeinen nicht funktioniert, da jedes ``öffnen oder schließen kann.
Es kann für besondere Fälle aufgrund von Glück oder besonderen Merkmalen funktionieren.


Update Januar 2016: Git 2.8 (März 2016) entfernt Backticks vollständig.

Sehen Sie verpflichten ec1b763 , begehen 9c10377 , begehen c7b793a , begehen 80a6b3f , begehen 9375dcf , begehen e74ef60 , begehen 27fe43e , begehen 2525c51 , begehen becd67f , begehen a5c98ac , begehen 8c311f9 , begehen 57da049 , begehen 1d9e86f , begehen 78ba28d , begehen efa639f , begehen 1be2fa0 , verpflichten 38e9476 , Commit 8823d2f , Commit 32858a0 , Commit cd914d8(12. Januar 2016) von Elia Pinto ( devzero2000) .
(Zusammengeführt von Junio ​​C Hamano - gitster- in Commit e572fef , 22. Januar 2016)

Ab Git 2.8 ist alles $(...)nicht mehr `...`.

VonC
quelle
2
$()ist auch POSIX-spezifiziert - ein Zitat, das Backticks als "POSIX-unterstützt" beschreibt, so dass impliziert wird, dass dies nur für sie gilt, ist irreführend. Es ist nur (vor den 1970er Jahren) vor POSIX Bourne, wo Backticks die einzige unterstützte Syntax sind.
Charles Duffy
25

Wenn das ältere Back-Tick-Formular verwendet wird, behält der Backslash seine wörtliche Bedeutung bei, außer wenn $, `oder \ folgen. Der erste Back-Tick, dem kein Backslash vorangestellt ist, beendet die Befehlsersetzung.

Bei Verwendung des neueren $(command)Formulars bilden alle Zeichen zwischen den Klammern den Befehl. keine werden speziell behandelt.

Beide Formen können verschachtelt werden, für die Back-Tick-Variante ist jedoch die folgende Form erforderlich.

`echo \`foo\`` 

Im Gegensatz zu:

$(echo $(foo))
ocodo
quelle
1
Kleinere Korrekturen, sowohl die Backtick-Version als auch die $()Version sind POSIX-kompatibel.
SiegeX
5

Es gibt kaum einen Unterschied, außer welchen nicht entflohenen Zeichen Sie innerhalb des Befehls verwenden können. Sie können sogar `...` Befehle in $ (...) (und umgekehrt) einfügen, um eine kompliziertere Befehlsersetzung mit zwei Ebenen zu erreichen.

Es gibt eine etwas andere Interpretation des Backslash-Zeichens / Operators. Unter anderem beim Schachteln `...` Substitution Befehle, müssen Sie die inneren entkommen ` Zeichen mit \, während bei $ () Substitutions es die Verschachtelung automatisch versteht.

DigitalRoss
quelle
0

"Was ist der Unterschied zwischen den beiden Methoden?"

Achten Sie auf dieses Verhalten:

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

Sie erhalten folgende Ergebnisse:

$A
A_VARIABLE

 

Hiro
quelle