Qual è la differenza tra $ (comando) e `comando` nella programmazione della shell?


258

Per memorizzare l'output di un comando come variabile in sh / ksh / bash, puoi fare entrambe le cose

var=$(command)

o

var=`command`

Qual è la differenza tra i due metodi?


29
Si prega di consultare BashFAQ / 082 .
In pausa fino a nuovo avviso.

Troverai il problema nidificato dettagliato nelle Linee guida per la codifica Git: vedi la mia risposta di seguito .
VonC,

Risposte:


274

I backtick / segni di grave sono stati deprecati a favore della $()sostituzione del comando perché $()possono facilmente nidificarsi dentro di sé come in $(echo foo$(echo bar)). Esistono altre differenze come il modo in cui le barre rovesciate vengono analizzate nella versione backtick / gravemark, ecc.

Vedi BashFAQ / 082 per diversi motivi per preferire sempre la sintassi $ (...).

Vedi anche le specifiche POSIX per informazioni dettagliate sulle varie differenze.


25
Buon collegamento, ma quel testo non deprecava i backquotes in favore di $(...)- li nota solo come alternative.
Norman Gray,

24
@NormanGray POSIX potrebbe non dire la parola deprecata ma dice "the backquoted variety of command substitution is not recommended"che è solo un modo lungo e tortuoso di dire IMHO deprecato
SiegeX

11
POSIX non ha deprecato i backtick, ma piuttosto aggiunto $(...)come metodo alternativo. Non sono noti bug di implementazione con backtick, ma ci sono molti bug di implementazione noti $(...) . Pertanto, per problemi di portabilità, si consiglia di utilizzare i backtick per le chiamate non nidificate. $(...)ha bisogno di un parser ricorsivo ma questo non è stato usato con ksh86 che ha introdotto la funzione. Controllare in-ulm.de/~mascheck/various/cmd-subst per un elenco delle implementazioni corrette. Una shell conforme deve supportare tutti i casi tranne il caso D.2.
schily

2
In POSIX ci sono altre cose che devono essere viste come deprecated, ad esempio, l'uso waitpid()che impedisce di vedere tutti i 32 bit dal exit()parametro, ma tutte le shell tranne la recente Bourne Shell usano ancora waitpid()invece della waitid()chiamata che è ora disponibile da 26 anni
schily,

Il link nella risposta suggerisce che ci sono alcune differenze tra i backtick e $(), che è più spiegato in questa parte della documentazione . Le differenze non riguardano solo la nidificazione.
Qualche programmatore, amico, il

39

Si comportano allo stesso modo. La differenza è sintattica: è più facile nidificare $()di ``:

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

vs.

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

10
echo $(echo \$abc)Non è la stessa echo `echo \$abc`‍- esistono anche differenze per $(echo \`)e $(echo \\)
Peter.O

Un'altra differenza è: echo foo `#comment`vs echo foo $(#comment). Il secondo non funziona. (Utilizzato per commentare in un comando multilinea.)
wisbucky

27

Luglio 2014: il commit f25f5e6 (di Elia Pinto ( devzero2000) , aprile 2014, Git 2.0) aggiunge al problema della nidificazione:

Il modulo retroquisito è il metodo tradizionale per la sostituzione dei comandi ed è supportato da POSIX.
Tuttavia, tutti gli usi tranne quelli più semplici si complicano rapidamente.
In particolare, le sostituzioni di comandi incorporate e / o l'uso di virgolette doppie richiedono un'attenta evasione con il carattere barra rovesciata
.

Ecco perché la git / Documentation / CodingGuidelines menziona:

Preferiamo la $( ... )sostituzione dei comandi; a differenza di ``, nidifica correttamente .
Avrebbe dovuto essere il modo in cui Bourne l'ha scritto fin dal primo giorno, ma sfortunatamente non lo è.

thiton ha commentato :

Questo è il motivo `echo `foo`` per cui non funzionerà in generale a causa dell'ambiguità intrinseca perché ognuno ``può aprirsi o chiudersi.
Potrebbe funzionare per casi speciali a causa di fortuna o funzionalità speciali.


Aggiornamento gennaio 2016: Git 2.8 (marzo 2016) elimina completamente i backtick.

Vedi commit ec1b763 , commit 9c10377 , commettere c7b793a , commettere 80a6b3f , commettere 9375dcf , commettere e74ef60 , commettere 27fe43e , commettere 2525c51 , commettere becd67f , commettere a5c98ac , commettere 8c311f9 , commettere 57da049 , commettere 1d9e86f , commettere 78ba28d , commettere efa639f , commettere 1be2fa0 , commettono 38e9476 , commit 8823d2f , commit 32858a0 , commit cd914d8(12 gennaio 2016) di Elia Pinto (devzero2000) .
(Unita da Junio ​​C Hamano - gitster- in commit e572fef , 22 gen 2016)

Da Git 2.8 in poi, è tutto $(...), non di più `...`.


2
$()è anche specificato POSIX - una citazione che descrive i backtick come "supportati da POSIX" in modo tale da implicare che ciò sia unico per loro è fuorviante. È solo (Bourne pre-POSIX dell'era degli anni '70) che i backtick sono l'unica sintassi supportata.
Charles Duffy

25

Quando viene utilizzato il vecchio modulo di back-tick, backslash mantiene il suo significato letterale tranne quando seguito da $, `o \. Il primo segno di spunta non preceduto da una barra rovesciata termina la sostituzione del comando.

Quando si utilizza il più recente $(command) modulo , tutti i caratteri tra parentesi formano il comando; nessuno è trattato in modo speciale.

Entrambi i moduli possono essere nidificati, ma la varietà back-tick richiede il seguente modulo.

`echo \`foo\`` 

Al contrario di:

$(echo $(foo))

1
Correzione minore, sia la versione backtick che la $()versione sono conformi a POSIX.
SiegeX,

5

C'è poca differenza, ad eccezione dei caratteri senza caratteri di escape che è possibile utilizzare all'interno del comando. Puoi anche inserire i comandi `...` all'interno di $ (...) (e viceversa) per una sostituzione dei comandi più complessa a due livelli.

Esiste un'interpretazione leggermente diversa del carattere / operatore della barra rovesciata. Tra le altre cose, quando si annidano i comandi di sostituzione `...` , è necessario sfuggire ai caratteri interni ` con \, mentre con la sottostazione $ () capisce automaticamente l'annidamento.


0

"Qual è la differenza tra i due metodi?"

Fai attenzione a questo comportamento:

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

Otterrai questi risultati:

$A
A_VARIABLE

 

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.