tl; dr
Eine Sohle stuff
würde höchstwahrscheinlich für Sie arbeiten.
Volle Antwort
Was geschieht
Wenn Sie rennen foo $(stuff)
, passiert Folgendes:
stuff
läuft;
- seine Ausgabe (stdout) ersetzt, anstatt gedruckt zu werden,
$(stuff)
beim Aufruf von foo
;
- Wenn es
foo
dann ausgeführt wird, hängen seine Befehlszeilenargumente offensichtlich davon ab, was stuff
zurückgegeben wurde.
Dieser $(…)
Mechanismus wird "Befehlssubstitution" genannt. In Ihrem Fall ist der Hauptbefehl, echo
der im Grunde seine Befehlszeilenargumente an stdout ausgibt. Was auch immer stuff
versucht, auf stdout zu drucken, wird erfasst, an stdout übergeben echo
und von auf stdout gedruckt echo
.
Wenn Sie möchten, dass die Ausgabe von stuff
auf stdout gedruckt wird, führen Sie einfach die Sohle aus stuff
.
Die `…`
Syntax dient demselben Zweck wie $(…)
(unter demselben Namen: "Befehlssubstitution"), es gibt jedoch nur wenige Unterschiede, sodass Sie sie nicht blind austauschen können. Siehe diese FAQ und diese Frage .
Sollte ich echo $(stuff)
egal was vermeiden ?
Es gibt einen Grund, den Sie verwenden möchten, echo $(stuff)
wenn Sie wissen, was Sie tun. Aus dem gleichen Grund sollten Sie vermeiden, echo $(stuff)
wenn Sie nicht wirklich wissen, was Sie tun.
Der Punkt ist stuff
und echo $(stuff)
sind nicht genau gleichwertig. Letzteres bedeutet, dass der Operator split + glob für die Ausgabe von stuff
mit dem Standardwert von aufgerufen wird $IFS
. Doppelte Anführungszeichen für die Befehlsersetzung verhindern dies. Wenn die Befehlsersetzung in einfache Anführungszeichen gesetzt wird, handelt es sich nicht mehr um eine Befehlsersetzung.
Um dies beim Aufteilen zu beobachten, führen Sie die folgenden Befehle aus:
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")'
Und zum Verschlingen:
echo "/*"
echo $(echo "/*")
echo "$(echo "/*")" # the shell is smart enough to identify the inner and outer quotes
echo '$(echo "/*")'
Wie Sie sehen, echo "$(stuff)"
ist äquivalent (-ish *) zu stuff
. Sie könnten es benutzen, aber was bringt es, die Dinge auf diese Weise zu komplizieren?
Auf der anderen Seite , wenn Sie wollen die Ausgabe von stuff
Splitting + zu unterziehen Globbing dann Sie können finden echo $(stuff)
nützlich. Es muss jedoch Ihre bewusste Entscheidung sein.
Es gibt Befehle, die eine Ausgabe generieren, die ausgewertet werden sollte (einschließlich Teilen, Verschieben und mehr) und von der Shell ausgeführt eval "$(stuff)"
wird. Dies ist eine Möglichkeit (siehe diese Antwort ). Ich habe noch nie einen Befehl gesehen, dessen Ausgabe vor dem Drucken einer zusätzlichen Aufteilung + Globe unterzogen werden muss . Bewusstes Verwenden echo $(stuff)
scheint sehr ungewöhnlich.
Was ist var=$(stuff); echo "$var"
?
Guter Punkt. Dieser Ausschnitt:
var=$(stuff)
echo "$var"
sollte äquivalent sein zu echo "$(stuff)"
äquivalent (-ish *) zu stuff
. Wenn es sich um den gesamten Code handelt, führen Sie ihn stuff
stattdessen aus.
Wenn Sie die Ausgabe jedoch stuff
mehrmals verwenden müssen, verwenden Sie diesen Ansatz
var=$(stuff)
foo "$var"
bar "$var"
ist normalerweise besser als
foo "$(stuff)"
bar "$(stuff)"
Selbst wenn dies der Fall foo
ist echo
und Sie echo "$var"
in Ihren Code aufgenommen werden, ist es möglicherweise besser, dies so zu belassen. Dinge, die man beachten muss:
- Mit
var=$(stuff)
stuff
läuft einmal; Selbst wenn der Befehl schnell ist, ist es das Richtige, zu vermeiden, dass dieselbe Ausgabe zweimal berechnet wird. Oder hat möglicherweise stuff
andere Auswirkungen als das Schreiben in stdout (z. B. Erstellen einer temporären Datei, Starten eines Dienstes, Starten einer virtuellen Maschine, Benachrichtigen eines Remoteservers), sodass Sie ihn nicht mehrmals ausführen möchten.
- Wenn
stuff
zeitabhängige oder etwas zufällige Ausgaben generiert werden, erhalten Sie möglicherweise inkonsistente Ergebnisse von foo "$(stuff)"
und bar "$(stuff)"
. Nach var=$(stuff)
dem Wert $var
festgelegt ist , und Sie können sicher sein , foo "$var"
und bar "$var"
identisches Befehlszeilenargument bekommen.
In einigen Fällen foo "$var"
möchten (müssen) Sie möglicherweise anstelle von verwenden foo $var
, insbesondere wenn mehrere Argumente für stuff
generiert werden (eine Array-Variable ist möglicherweise besser, wenn Ihre Shell dies unterstützt). Weißt du nochmal, was du tust? Wenn es um den Unterschied zwischen und geht, ist er der gleiche wie zwischen und .foo
echo
echo $var
echo "$var"
echo $(stuff)
echo "$(stuff)"
* Äquivalent ( -ish )?
Ich sagte echo "$(stuff)"
ist gleichbedeutend mit stuff
. Es gibt mindestens zwei Probleme, die es nicht genau gleichwertig machen:
$(stuff)
läuft stuff
es in einer Subshell, so besser zu sagen , echo "$(stuff)"
entspricht (ish) zu (stuff)
. Befehle, die sich auf die Shell auswirken, in der sie ausgeführt werden, wirken sich in einer Subshell nicht auf die Hauptshell aus.
In diesem Beispiel stuff
ist a=1; echo "$a"
:
a=0
echo "$(a=1; echo "$a")" # echo "$(stuff)"
echo "$a"
Vergleichen Sie es mit
a=0
a=1; echo "$a" # stuff
echo "$a"
und mit
a=0
(a=1; echo "$a") # (stuff)
echo "$a"
Beginnen Sie mit stuff
einem anderen Beispiel cd /; pwd
:
cd /bin
echo "$(cd /; pwd)" # echo "$(stuff)"
pwd
und Test stuff
und (stuff)
Versionen.
echo
ist kein gutes Werkzeug, um unkontrollierte Daten anzuzeigen . Das, echo "$var"
worüber wir gesprochen haben, hätte sein sollen printf '%s\n' "$var"
. Aber da die Frage erwähnt echo
und die wahrscheinlichste Lösung darin besteht, sie überhaupt nicht zu verwenden echo
, habe ich mich entschlossen, printf
sie bis jetzt nicht vorzustellen .
stuff
oder (stuff)
verschachtelt echo $(stuff)
die Ausgabe von stdout und stderr, während die gesamte Ausgabe von stderr stuff
(die zuerst ausgeführt wird) und erst dann die Ausgabe von stdout gedruckt wird, die von echo
(die zuletzt ausgeführt wird) verdaut wurde .
$(…)
Entfernt alle nachfolgenden Zeilenumbrüche und echo
fügt sie dann wieder hinzu. So echo "$(printf %s 'a')" | xxd
ergibt sich eine andere Ausgabe als printf %s 'a' | xxd
.
Einige Befehle ( ls
zum Beispiel) funktionieren unterschiedlich, je nachdem, ob die Standardausgabe eine Konsole ist oder nicht. so ls | cat
tut es nicht dasselbe ls
. Ähnlich echo $(ls)
wird anders funktionieren als ls
.
Putting ls
in einem allgemeinen Fall beiseite, wenn Sie das andere Verhalten zu zwingen , haben dann stuff | cat
als besser echo $(ls)
oder echo "$(ls)"
weil es alle anderen Themen erwähnt hier nicht ausgelöst hat.
Möglicherweise abweichender Exit-Status (zur Vervollständigung dieser Wiki-Antwort genannt; für Details siehe eine andere Antwort , die Anerkennung verdient).