Okay, lass uns das zusammenfassen. Eine Subshell führt ihren Inhalt in einer Kette aus (dh sie gruppiert sie). Dies ist tatsächlich intuitiv sinnvoll, da eine Unterschale einfach durch Umgeben der Befehlskette mit erstellt wird ()
. Abgesehen davon, dass der Inhalt der Subshell bei der Ausführung zusammengefasst wird, können Sie eine Subshell weiterhin so verwenden, als wäre es ein einzelner Befehl. Das heißt, eine Unterschale hat immer noch eine stdin
, stdout
und stderr
so können Sie Dinge zu und von einer Unterschale leiten.
Andererseits ist das Ersetzen von Befehlen nicht dasselbe wie das einfache Verketten von Befehlen. Die Befehlssubstitution soll sich eher wie ein variabler Zugriff verhalten, jedoch mit einem Funktionsaufruf. Im Gegensatz zu Befehlen verfügen Variablen nicht über die Standard-Dateideskriptoren, sodass Sie (im Allgemeinen) nichts zu oder von einer Variablen weiterleiten können. Dies gilt auch für Befehlsersetzungen.
Um dies klarer zu machen, folgen eine Reihe von möglicherweise unklaren (aber genauen) Beispielen und eine Reihe von, wie ich denke, besser verständlichen Beispielen.
Angenommen, der date -u
Befehl gibt Folgendes aus:
Thu Jul 2 13:42:27 UTC 2015
Wir möchten jedoch die Ausgabe dieses Befehls bearbeiten. Also, lasst es uns in etwas wie sed
:
$ date -u | sed -e 's/ / /g'
Thu Jul 2 13:42:27 UTC 2015
Wow, das hat Spaß gemacht! Das Folgende entspricht vollständig dem oben Gesagten (abgesehen von einigen Umgebungsunterschieden, über die Sie in den Manpages zu Ihrer Shell lesen können):
$ (date -u) | sed -e 's/ / /g'
Thu Jul 2 13:42:27 UTC 2015
Das sollte keine Überraschung sein, da wir nur eine Gruppe gemacht haben date -u
. Wenn wir jedoch Folgendes tun, werden wir etwas bekommen, das auf den ersten Blick etwas seltsam erscheint:
$ $(date -u) | sed -e 's/ / /g'
command not found: Thu
Dies liegt daran $(date -u)
, dass Sie genau eingeben müssen, welche date -u
Ausgaben ausgegeben werden sollen. Das oben Gesagte entspricht also dem Folgenden:
$ Thu Jul 2 13:42:27 UTC 2015 | sed -e 's/ / /g'
Was natürlich fehlerhaft sein wird, weil Thu
es kein Befehl ist (zumindest keiner, den ich kenne); und es leitet sicher nichts weiter stdout
( sed
wird also niemals eine Eingabe bekommen).
Da wir jedoch wissen, dass Befehlssubstitutionen wie Variablen wirken, können wir dieses Problem leicht beheben, da wir wissen, wie der Wert einer Variablen in einen anderen Befehl übertragen wird:
$ echo $(date -u) | sed -e 's/ / /g'
Thu Jul 2 13:42:27 UTC 2015
Aber wie bei jeder Variablen in bash sollten Sie wahrscheinlich Befehlsersetzungen mit zitieren ""
.
Nun zum vielleicht einfacheren Beispiel; Folgendes berücksichtigen:
$ pwd
/home/hypothetical
$ echo pwd
pwd
$ echo "$(pwd)"
/home/hypothetical
$ echo "$HOME"
/home/hypothetical
$ echo (pwd)
error: your shell will tell you something weird that roughly means “Whoa! you tried to have me echo something that isn't text!”
$ (pwd)
/home/hypothetical
Ich bin mir nicht sicher, wie ich es einfacher beschreiben soll. Die Befehlssubstitution funktioniert genau wie ein variabler Zugriff, bei dem die Subshell weiterhin wie ein Befehl funktioniert.
netcat
da es sich nur um bloßen Text handelt. Wenn Sie beispielsweiseecho
vor Beginn der Befehlsersetzung hinzugefügt haben, stellen Sie möglicherweise fest, dass dies funktioniert.