@heemayl Danke. Können Sie die Unterschiede in meinem Fall herausarbeiten? Vielen Dank.
Nam G VU
1
Hinweis: Die Befehle auf beiden Seiten |werden in Subshells ausgeführt.
Heemayl
Antworten:
21
In p=$(cd ~ && pwd):
Die Befehlsersetzung $()wird in einer Subshell ausgeführt
cd ~Wechselt das Verzeichnis in ~(Ihr Zuhause). Wenn dies cderfolgreich ist ( &&), wird pwdder Verzeichnisname auf STDOUT gedruckt. Die Zeichenfolge, in der gespeichert wurde, pist also Ihr Zuhause-Verzeichnis, z/home/foobar
In p=$(cd ~ | pwd):
$()Bringt wieder eine Subshell hervor
Die Befehle auf beiden Seiten |werden in den jeweiligen Subshells ausgeführt (und beide werden gleichzeitig gestartet).
so cd ~wird in einer Subshell, und fertig pwdin einem separaten Sub - Shell
Sie würden also nur das STDOUT erhalten, pwddh von wo aus Sie den Befehl ausführen. Dies kann ein beliebiges Verzeichnis sein, wie Sie sich vorstellen können. Daher penthält es den Verzeichnisnamen, von dem aus der Befehl aufgerufen wird, und nicht Ihr Ausgangsverzeichnis
Was ist der Zweck der Pipe zwischen den Befehlen? cd ~erzeugt keine Ausgabe und pwdliest keine Eingabe.
Barmar
Der zweite Befehl ist im wesentlichen äquivalent (cd ~);p=$(pwd)ist , nicht wahr?
Barmar
@Barmar Ja, es ist das, was OP verwendet hat, und ich erkläre es nur für ihn.
Heemayl
6
Das Kernproblem ist, wie die Operatoren &&und |die beiden Befehle verbinden.
Das &&verbindet die Befehle über den Exit-Code. Das |verbindet die beiden Befehle über die Dateideskriptoren (stdin, stdout).
Vereinfachen wir zuerst. Wir können die Zuordnung aufheben und schreiben:
echo $(cd ~&& pwd)
echo $(cd ~| pwd)
Wir können sogar die Unter-Shell für die Befehlsausführung entfernen, um dies zu analysieren:
$ cd ~&& pwd
$ cd ~| pwd
&&
Wenn wir die Eingabeaufforderung ändern, um das Verzeichnis anzuzeigen, in dem die Befehle ausgeführt werden PS1='\w\$ ', sehen wir etwa Folgendes:
/tmp/user$ cd ~&& pwd
/home/user
~$
Der Befehl cd ~hat das "aktuelle Verzeichnis" in das Home des Benutzers geändert, der den Befehl ausführt ( /home/user).
Nachdem der Befehl erfolgreich ausgeführt wurde (Beendigungscode 0), wird der nächste Befehl nach dem && ausgeführt
Und das "aktuelle Arbeitsverzeichnis" wird gedruckt.
Die laufende Shell wurde in geändert pwd, ~wie durch die Eingabeaufforderung von angezeigt ~$.
Wenn die Änderung des Verzeichnisses aus irgendeinem Grund nicht erfolgreich war (Exit-Code nicht 0) (Verzeichnis existiert nicht, Berechtigungen blockieren das Lesen des Verzeichnisses), wird der nächste Befehl nicht ausgeführt.
Beispiel:
/tmp/user$ false && pwd
/tmp/user$ _
Der Exit-Code von 1 von falseverhindert die Ausführung des nächsten Befehls.
Somit ist der Beendigungscode von "Befehl 1" derjenige, der den "Befehl 2" beeinflusst.
Das Verzeichnis wurde geändert, aber innerhalb einer Sub-Shell $(…)wird das geänderte Verzeichnis gedruckt /home/user, aber sofort verworfen, wenn die Sub-Shell geschlossen wird. Das pwd kehrt zum Ausgangsverzeichnis ( /tmp/user) zurück.
|
Das ist, was passiert:
/tmp/user$ cd ~| pwd
/tmp/user
/tmp/user$ _
Das Metazeichen |(kein echter Operator) weist die Shell an, ein sogenanntes "Pipe" (in Bash) zu erstellen. Jeder Befehl auf jeder Seite der Pipe ( |) wird in jede eigene Unterschale gesetzt, zuerst die rechte Seite Befehl, dann der linke. Der Eingabedateideskriptor ( /dev/stdin) des rechten Befehls wird mit dem Ausgabedeskriptor ( /dev/stdout) verbunden. Anschließend werden beide Befehle gestartet und können miteinander interagieren. Der linke Befehl ( cd -) hat keine Ausgabe und der rechte Befehl ( pwd) akzeptiert auch keine Eingabe. Jeder läuft also unabhängig in jeder eigenen Sub-Shell.
Das cd ~ändert die pwd einer Shell.
Das pwddruckt das (völlig unabhängige) PWD der anderen Unterschale.
Die Änderungen an jeder Shell werden verworfen, wenn die Pipe endet. Die externe Sub-Shell hat die PWD nicht geändert.
Deshalb sind die beiden Befehle nur durch "Dateideskriptoren" verbunden.
In diesem Fall wird nichts gesendet und nichts gelesen.
Der ganze Befehl:
$ echo "$(cd ~ | pwd)"
Gibt nur das Verzeichnis aus, in dem der Befehl ausgeführt wurde.
Ich bin mir nicht sicher, ob du '|' oder '||' in deinem zweiten Fall.
'|' In einer Shell wird die Ausgabe eines Befehls an die Eingabe eines anderen weitergeleitet. Ein häufiger Anwendungsfall ist etwa:
curl http://abcd.com/efgh | grep ijkl
Führen Sie einen Befehl aus und verwenden Sie einen anderen Befehl, um die Ausgabe eines Befehls zu verarbeiten.
In dem von Ihnen angegebenen Beispiel ist dies ziemlich unsinnig, da "cd" normalerweise keine Ausgabe generiert und "pwd" keine Eingabe erwartet.
'&&' und '||' sind jedoch Partnerbefehle. Sie sind so konzipiert, dass sie in den meisten Sprachen wie logische Operatoren "und" und "oder" verwendet werden. Die durchgeführten Optimierungen geben ihnen jedoch ein spezifisches Verhalten, das einem Shell-Programmierparadigma entspricht.
Um das Ergebnis einer logischen "und" -Operation zu ermitteln, müssen Sie die zweite Bedingung nur auswerten, wenn die erste Bedingung erfolgreich ist. Wenn die erste Bedingung fehlschlägt, ist das Gesamtergebnis immer falsch.
Um das Ergebnis einer logischen "oder" Operation zu ermitteln, müssen Sie die zweite Bedingung nur auswerten, wenn die erste Bedingung fehlschlägt. Wenn die erste Bedingung erfolgreich ist, ist das Gesamtergebnis immer wahr.
Also, in der Shell, wenn Sie command1 && command2command2nur ausgeführt werden, wenn command1abgeschlossen und ein erfolgreicher Ergebniscode zurückgegeben hat. Wenn dies command1 || command2command2der Fall ist, wird es ausgeführt, command1wenn command1ein Fehlercode zurückgegeben wird.
Ein weiteres gängiges Paradigma ist, einen Testbefehl zu haben command1- dies erzeugt eine einfache if / then-Anweisung - zum Beispiel:
[ "$VAR" = "" ] && VAR="Value if empty"
Ist eine (langwierige) Möglichkeit, einer Variablen einen Wert zuzuweisen, wenn sie aktuell leer ist.
Es gibt viele Beispiele für die Verwendung dieses Prozesses an anderer Stelle in Stack Exchange
|
werden in Subshells ausgeführt.Antworten:
In
p=$(cd ~ && pwd)
:Die Befehlsersetzung
$()
wird in einer Subshell ausgeführtcd ~
Wechselt das Verzeichnis in~
(Ihr Zuhause). Wenn diescd
erfolgreich ist (&&
), wirdpwd
der Verzeichnisname auf STDOUT gedruckt. Die Zeichenfolge, in der gespeichert wurde,p
ist also Ihr Zuhause-Verzeichnis, z/home/foobar
In
p=$(cd ~ | pwd)
:$()
Bringt wieder eine Subshell hervorDie Befehle auf beiden Seiten
|
werden in den jeweiligen Subshells ausgeführt (und beide werden gleichzeitig gestartet).so
cd ~
wird in einer Subshell, und fertigpwd
in einem separaten Sub - ShellSie würden also nur das STDOUT erhalten,
pwd
dh von wo aus Sie den Befehl ausführen. Dies kann ein beliebiges Verzeichnis sein, wie Sie sich vorstellen können. Daherp
enthält es den Verzeichnisnamen, von dem aus der Befehl aufgerufen wird, und nicht Ihr Ausgangsverzeichnisquelle
cd ~
erzeugt keine Ausgabe undpwd
liest keine Eingabe.(cd ~);p=$(pwd)
ist , nicht wahr?Das Kernproblem ist, wie die Operatoren
&&
und|
die beiden Befehle verbinden.Das
&&
verbindet die Befehle über den Exit-Code. Das|
verbindet die beiden Befehle über die Dateideskriptoren (stdin, stdout).Vereinfachen wir zuerst. Wir können die Zuordnung aufheben und schreiben:
Wir können sogar die Unter-Shell für die Befehlsausführung entfernen, um dies zu analysieren:
&&
Wenn wir die Eingabeaufforderung ändern, um das Verzeichnis anzuzeigen, in dem die Befehle ausgeführt werden
PS1='\w\$ '
, sehen wir etwa Folgendes:cd ~
hat das "aktuelle Verzeichnis" in das Home des Benutzers geändert, der den Befehl ausführt (/home/user
).pwd
,~
wie durch die Eingabeaufforderung von angezeigt~$
.Wenn die Änderung des Verzeichnisses aus irgendeinem Grund nicht erfolgreich war (Exit-Code nicht 0) (Verzeichnis existiert nicht, Berechtigungen blockieren das Lesen des Verzeichnisses), wird der nächste Befehl nicht ausgeführt.
Beispiel:
Der Exit-Code von 1 von
false
verhindert die Ausführung des nächsten Befehls.Somit ist der Beendigungscode von "Befehl 1" derjenige, der den "Befehl 2" beeinflusst.
Nun die Auswirkungen des gesamten Befehls:
Das Verzeichnis wurde geändert, aber innerhalb einer Sub-Shell
$(…)
wird das geänderte Verzeichnis gedruckt/home/user
, aber sofort verworfen, wenn die Sub-Shell geschlossen wird. Das pwd kehrt zum Ausgangsverzeichnis (/tmp/user
) zurück.|
Das ist, was passiert:
Das Metazeichen
|
(kein echter Operator) weist die Shell an, ein sogenanntes "Pipe" (in Bash) zu erstellen. Jeder Befehl auf jeder Seite der Pipe (|
) wird in jede eigene Unterschale gesetzt, zuerst die rechte Seite Befehl, dann der linke. Der Eingabedateideskriptor (/dev/stdin
) des rechten Befehls wird mit dem Ausgabedeskriptor (/dev/stdout
) verbunden. Anschließend werden beide Befehle gestartet und können miteinander interagieren. Der linke Befehl (cd -
) hat keine Ausgabe und der rechte Befehl (pwd
) akzeptiert auch keine Eingabe. Jeder läuft also unabhängig in jeder eigenen Sub-Shell.cd ~
ändert die pwd einer Shell.pwd
druckt das (völlig unabhängige) PWD der anderen Unterschale.Die Änderungen an jeder Shell werden verworfen, wenn die Pipe endet. Die externe Sub-Shell hat die PWD nicht geändert.
Deshalb sind die beiden Befehle nur durch "Dateideskriptoren" verbunden.
In diesem Fall wird nichts gesendet und nichts gelesen.
Der ganze Befehl:
Gibt nur das Verzeichnis aus, in dem der Befehl ausgeführt wurde.
quelle
Ich bin mir nicht sicher, ob du '|' oder '||' in deinem zweiten Fall.
'|' In einer Shell wird die Ausgabe eines Befehls an die Eingabe eines anderen weitergeleitet. Ein häufiger Anwendungsfall ist etwa:
curl http://abcd.com/efgh | grep ijkl
Führen Sie einen Befehl aus und verwenden Sie einen anderen Befehl, um die Ausgabe eines Befehls zu verarbeiten.In dem von Ihnen angegebenen Beispiel ist dies ziemlich unsinnig, da "cd" normalerweise keine Ausgabe generiert und "pwd" keine Eingabe erwartet.
'&&' und '||' sind jedoch Partnerbefehle. Sie sind so konzipiert, dass sie in den meisten Sprachen wie logische Operatoren "und" und "oder" verwendet werden. Die durchgeführten Optimierungen geben ihnen jedoch ein spezifisches Verhalten, das einem Shell-Programmierparadigma entspricht.
Um das Ergebnis einer logischen "und" -Operation zu ermitteln, müssen Sie die zweite Bedingung nur auswerten, wenn die erste Bedingung erfolgreich ist. Wenn die erste Bedingung fehlschlägt, ist das Gesamtergebnis immer falsch.
Um das Ergebnis einer logischen "oder" Operation zu ermitteln, müssen Sie die zweite Bedingung nur auswerten, wenn die erste Bedingung fehlschlägt. Wenn die erste Bedingung erfolgreich ist, ist das Gesamtergebnis immer wahr.
Also, in der Shell, wenn Sie
command1 && command2
command2
nur ausgeführt werden, wenncommand1
abgeschlossen und ein erfolgreicher Ergebniscode zurückgegeben hat. Wenn diescommand1 || command2
command2
der Fall ist, wird es ausgeführt,command1
wenncommand1
ein Fehlercode zurückgegeben wird.Ein weiteres gängiges Paradigma ist, einen Testbefehl zu haben
command1
- dies erzeugt eine einfache if / then-Anweisung - zum Beispiel:[ "$VAR" = "" ] && VAR="Value if empty"
Ist eine (langwierige) Möglichkeit, einer Variablen einen Wert zuzuweisen, wenn sie aktuell leer ist.
Es gibt viele Beispiele für die Verwendung dieses Prozesses an anderer Stelle in Stack Exchange
quelle