tl; dr
Eine Sohle stuff
würde höchstwahrscheinlich für Sie arbeiten.
Volle Antwort
Was geschieht
Wenn du rennst foo $(stuff)
, passiert Folgendes:
stuff
läuft;- seine Ausgabe (stdout) ersetzt nicht
$(stuff)
den Ausdruck, sondern ersetzt den Aufruf vonfoo
; - dann ausgeführt
foo
, hängen die Befehlszeilenargumente offensichtlich von den zurückgegebenen Werten abstuff
.
Dieser $(…)
Mechanismus wird als "Befehlssubstitution" bezeichnet. In Ihrem Fall gibt der Hauptbefehl die Befehlszeilenargumente echo
grundsätzlich an stdout aus. Was immer stuff
versucht, auf stdout zu drucken, wird erfasst, an echo
stdout von und von dort gedruckt echo
.
Wenn Sie möchten, dass die Ausgabe von stuff
stdout gedruckt wird, führen Sie einfach die Sohle aus stuff
.
Die `…`
Syntax hat den gleichen Zweck wie $(…)
(unter dem gleichen Namen: "Befehlsersetzung"), es gibt jedoch einige 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 demselben Grund sollten Sie es vermeiden, echo $(stuff)
wenn Sie nicht wirklich wissen, was Sie tun.
Der Punkt ist stuff
und echo $(stuff)
ist nicht genau gleichwertig. Letzteres bedeutet, dass Sie den split + glob-Operator für die Ausgabe von stuff
mit dem Standardwert von aufrufen $IFS
. Ein doppeltes Anführungszeichen der Befehlsersetzung verhindert dies. Einfaches Zitieren der Befehlsersetzung macht es nicht mehr zu einer Befehlsersetzung.
Um dies beim Splitten zu beobachten, führen Sie folgende 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 Globen:
echo "/*" echo $(echo "/*") echo "$(echo "/*")" # the shell is smart enough to identify the inner and outer quotes echo '$(echo "/*")'
Wie Sie sehen, echo "$(stuff)"
entspricht (-ish *) dem stuff
. Sie könnten es verwenden, aber was ist der Sinn, Dinge auf diese Weise zu komplizieren?
Auf der anderen Seite, wenn Sie möchten, dass die Ausgabe stuff
splitting + globbing durchläuft, können Sie dies für echo $(stuff)
nützlich halten. Es muss jedoch Ihre bewusste Entscheidung sein.
Es gibt Befehle, die eine Ausgabe generieren, die ausgewertet werden sollte (einschließlich Splitting, Globbing und mehr) und von der Shell ausgeführt wird. Es besteht also die eval "$(stuff)"
Möglichkeit (siehe diese Antwort ). Ich habe noch nie einen Befehl, der muss seinen Ausgang zu unterziehen zusätzliche Aufspaltung + Globbing, bevor sie gesehen gedruckt . Eine absichtliche Anwendung echo $(stuff)
scheint sehr ungewöhnlich zu sein.
Was ist var=$(stuff); echo "$var"
?
Guter Punkt. Dieser Ausschnitt:
var=$(stuff) echo "$var"
sollte echo "$(stuff)"
äquivalent sein (-ish *) zu stuff
. Wenn es sich um den gesamten Code handelt, führen Sie ihn einfach aus stuff
.
Wenn Sie jedoch die Ausgabe von stuff
mehr als einmal verwenden müssen, gehen Sie auf diese Weise vor
var=$(stuff) foo "$var" bar "$var"
ist normalerweise besser als
foo "$(stuff)" bar "$(stuff)"
Auch wenn foo
ist echo
und Sie erhalten echo "$var"
in Ihrem Code, kann es besser sein, es auf diese Weise zu halten. Dinge, die man beachten muss:
- Mit
var=$(stuff)
stuff
läuft einmal; Selbst wenn der Befehl schnell ist, sollten Sie vermeiden, dieselbe Ausgabe zweimal zu berechnen. Oder hat vielleichtstuff
andere Auswirkungen als das Schreiben in stdout (z. B. Erstellen einer temporären Datei, Starten eines Dienstes, Starten einer virtuellen Maschine, Benachrichtigen eines Remote-Servers), sodass Sie diese nicht mehrmals ausführen möchten. - Wenn
stuff
eine zeitabhängige oder etwas zufällige Ausgabe generiert wird, erhalten Sie möglicherweise inkonsistente Ergebnisse vonfoo "$(stuff)"
undbar "$(stuff)"
. Nachdemvar=$(stuff)
der Wert von$var
festgelegt ist, können Sie sicher seinfoo "$var"
undbar "$var"
ein identisches Befehlszeilenargument erhalten.
In einigen Fällen foo "$var"
möchten Sie (müssen) möglicherweise verwendet werden foo $var
, insbesondere wenn mehrere Argumente stuff
generiert werden (eine Array-Variable ist möglicherweise besser, wenn Ihre Shell dies unterstützt). Wieder wissen Sie, was Sie tun. Wenn es um den Unterschied zwischen und geht, ist das Gleiche wie zwischen und .foo
echo
echo $var
echo "$var"
echo $(stuff)
echo "$(stuff)"
* Äquivalent ( -ish )?
Ich sagte, echo "$(stuff)"
ist äquivalent (-ish) zu stuff
. Es gibt mindestens zwei Punkte, die es nicht genau gleichwertig machen:
$(stuff)
läuftstuff
in einer Subshell, es ist so besser zu sagen,echo "$(stuff)"
entspricht (ish) zu(stuff)
. Befehle, die sich auf die Shell beziehen, in der sie ausgeführt werden, wirken sich in einer Subshell nicht auf die Hauptshell aus.In diesem Beispiel
stuff
lauteta=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"
Ein weiteres Beispiel, beginnen Sie mit
stuff
Wesencd /; 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 sollenprintf '%s\n' "$var"
. Da die Frage jedoch erwähnt wirdecho
und die wahrscheinlichste Lösung nichtecho
in der ersten Anwendung ist, habe ich mich entschlossen, bisher keine Einführung zu findenprintf
.stuff
oder(stuff)
verschachteltecho $(stuff)
die Ausgabe von stdout und stderr, während die gesamte stderr-Ausgabe vonstuff
(die zuerst ausgeführt wird) gedruckt wird, und nur dann die stdout-Ausgabe, die vonecho
(die zuletzt ausgeführt wird) verdaut wird .$(…)
entfernt alle nachgestellten Zeilenumbrüche undecho
fügt sie dann zurück. Soecho "$(printf %s 'a')" | xxd
ergibt sich eine andere Ausgabe alsprintf %s 'a' | xxd
.Einige Befehle (
ls
zum Beispiel) funktionieren anders, je nachdem, ob die Standardausgabe eine Konsole ist oder nicht. sols | cat
tut nicht das gleichels
. Ähnlichecho $(ls)
wird anders funktionieren alsls
.Putting
ls
beiseite, in einem allgemeinen Fall, wenn Sie das andere Verhalten zu zwingen, haben dannstuff | cat
ist besser alsecho $(ls)
oderecho "$(ls)"
weil es löst nicht alle anderen Themen hier erwähnt.Möglicherweise anderer Exit-Status (erwähnt wegen der Vollständigkeit dieser Wiki-Antwort; für Details siehe eine andere Antwort, die Anerkennung verdient).