tl; dr
Una suola stuff
avrebbe molto probabilmente lavorare per voi.
Risposta completa
Che succede
Quando corri foo $(stuff)
, ecco cosa succede:
stuff
piste;
- il suo output (stdout), invece di essere stampato, sostituisce
$(stuff)
nell'invocazione di foo
;
- quindi
foo
viene eseguito, i suoi argomenti della riga di comando ovviamente dipendono da ciò che è stato stuff
restituito.
Questo $(…)
meccanismo si chiama "sostituzione comando". Nel tuo caso il comando principale è echo
che fondamentalmente stampa i suoi argomenti della riga di comando su stdout. Quindi qualunque cosa stuff
tenti di stampare su stdout viene catturato, passato echo
e stampato su stdout da echo
.
Se vuoi che l'output di stuff
sia stampato su stdout, esegui la suola stuff
.
La `…`
sintassi ha lo stesso scopo di $(…)
(con lo stesso nome: "sostituzione comando"), tuttavia ci sono alcune differenze, quindi non è possibile scambiarle ciecamente. Vedi queste FAQ e questa domanda .
Dovrei evitare echo $(stuff)
qualunque cosa?
C'è un motivo che potresti voler usare echo $(stuff)
se sai cosa stai facendo. Per lo stesso motivo dovresti evitare echo $(stuff)
se non sai davvero cosa stai facendo.
Il punto è stuff
e echo $(stuff)
non sono esattamente equivalenti. Quest'ultimo significa chiamare l'operatore split + glob sull'output di stuff
con il valore predefinito di $IFS
. La doppia citazione della sostituzione del comando impedisce questo. La virgoletta singola per la sostituzione del comando non la rende più una sostituzione di comando.
Per osservare questo quando si tratta di dividere eseguire questi comandi:
echo "a b"
echo $(echo "a b")
echo "$(echo "a b")" # the shell is smart enough to identify the inner and outer quotes
echo '$(echo "a b")'
E per globbing:
echo "/*"
echo $(echo "/*")
echo "$(echo "/*")" # the shell is smart enough to identify the inner and outer quotes
echo '$(echo "/*")'
Come puoi vedere echo "$(stuff)"
è equivalente (-ish *) a stuff
. Potresti usarlo ma che senso ha complicare le cose in questo modo?
D'altra parte, se si desidera che l'output di stuff
subisca la suddivisione + globbing, potrebbe essere echo $(stuff)
utile. Tuttavia, deve essere una tua decisione consapevole.
Ci sono comandi che generano output che dovrebbero essere valutati (che include split, globbing e altro) ed eseguiti dalla shell, quindi eval "$(stuff)"
è una possibilità (vedi questa risposta ). Non ho mai visto un comando che necessita del suo output per subire ulteriori scissioni + globbing prima di essere stampato . L'uso deliberato echo $(stuff)
sembra molto raro.
Che dire var=$(stuff); echo "$var"
?
Buon punto. Questo frammento:
var=$(stuff)
echo "$var"
dovrebbe essere equivalente a echo "$(stuff)"
equivalente (-ish *) a stuff
. Se è l'intero codice, esegui stuff
invece.
Se, tuttavia, è necessario utilizzare l'output di stuff
più di una volta, questo approccio
var=$(stuff)
foo "$var"
bar "$var"
di solito è meglio di
foo "$(stuff)"
bar "$(stuff)"
Anche se lo foo
è echo
e ottieni il echo "$var"
tuo codice, potrebbe essere meglio mantenerlo in questo modo. Cose da considerare:
- Con
var=$(stuff)
stuff
corse una volta; anche se il comando è veloce, evitare di calcolare due volte lo stesso output è la cosa giusta. O forse stuff
ha effetti diversi dalla scrittura su stdout (ad esempio la creazione di un file temporaneo, l'avvio di un servizio, l'avvio di una macchina virtuale, la notifica a un server remoto), quindi non si desidera eseguirlo più volte.
- Se
stuff
genera output dipendente dal tempo o in qualche modo casuale, è possibile ottenere risultati incoerenti da foo "$(stuff)"
e bar "$(stuff)"
. Dopo che var=$(stuff)
il valore di $var
è stato risolto, puoi essere sicuro foo "$var"
e bar "$var"
ottenere un argomento della riga di comando identico.
In alcuni casi, invece di foo "$var"
te, potresti voler (bisogno) usarlo foo $var
, specialmente se stuff
genera più argomenti per foo
(una variabile di matrice potrebbe essere migliore se la tua shell la supporta). Ancora una volta, sai cosa stai facendo. Quando si tratta echo
della differenza tra echo $var
e echo "$var"
è uguale a tra echo $(stuff)
e echo "$(stuff)"
.
* Equivalente ( -ish )?
Ho detto che echo "$(stuff)"
è equivalente (-ish) a stuff
. Esistono almeno due problemi che lo rendono non esattamente equivalente:
$(stuff)
viene eseguito stuff
in una subshell, quindi è meglio dire che echo "$(stuff)"
è equivalente (-ish) a (stuff)
. I comandi che influiscono sulla shell in cui sono in esecuzione, se in una subshell, non influiscono sulla shell principale.
In questo esempio stuff
è a=1; echo "$a"
:
a=0
echo "$(a=1; echo "$a")" # echo "$(stuff)"
echo "$a"
Confronta con
a=0
a=1; echo "$a" # stuff
echo "$a"
e con
a=0
(a=1; echo "$a") # (stuff)
echo "$a"
Un altro esempio, inizia con stuff
essere cd /; pwd
:
cd /bin
echo "$(cd /; pwd)" # echo "$(stuff)"
pwd
e test stuff
e (stuff)
versioni.
echo
non è un buon strumento per visualizzare dati non controllati . Questo di echo "$var"
cui stavamo parlando avrebbe dovuto essere printf '%s\n' "$var"
. Ma poiché la domanda menziona echo
e poiché la soluzione più probabile non è quella di utilizzare echo
in primo luogo, ho deciso di non presentarmi printf
fino ad ora.
stuff
oppure (stuff)
interleave l'output stdout e stderr, mentre echo $(stuff)
stampa tutto l'output stderr da stuff
(che viene eseguito per primo) e solo successivamente l'output stdout digerito da echo
(che viene eseguito per ultimo).
$(…)
rimuove qualsiasi nuova riga finale e quindi la echo
aggiunge nuovamente. Quindi echo "$(printf %s 'a')" | xxd
fornisce un output diverso rispetto a printf %s 'a' | xxd
.
Alcuni comandi ( ls
ad esempio) funzionano in modo diverso a seconda che l'output standard sia una console o meno; quindi ls | cat
non fa lo stesso ls
. Allo stesso modo echo $(ls)
funzionerà diversamente da ls
.
Mettendo ls
da parte, in un caso generale se devi forzare questo altro comportamento, allora stuff | cat
è meglio di echo $(ls)
o echo "$(ls)"
perché non scatena tutte le altre questioni menzionate qui.
Eventualmente diverso stato di uscita (menzionato per completezza di questa risposta wiki; per i dettagli vedere un'altra risposta che merita credito).