Vorrang von && vs & in bash und zsh

9

Bei der Beantwortung dieser Frage entdeckte ich einen sehr lustigen (und subtilen) Unterschied zwischen Verhalten in bashund zsh:

In bash:

romano@RRyS:~$ pwd
/home/romano
romano@RRyS:~$ alias x="cd /bin && ./echo A >/dev/null  &"
romano@RRyS:~$ x
[1] 16611
romano@RRyS:~$ pwd
/home/romano

Wie Sie sehen, wird die Ausführung des Alias xin einer Subshell ausgeführt, sodass sich das aktuelle Verzeichnis nicht ändert.

Nicht in zsh:

[romano:~] % pwd
/home/romano
[romano:~] % alias x="cd /bin && ./echo A >/dev/null &"
[romano:~] % x
[1] 16744
[1]  + 16744 done       ./echo A >/dev/null                                    
1& [romano:/bin] % pwd
/bin
[romano:/bin] % 

Hier wird das Verzeichnis geändert.

Es scheint, dass das &in basheine andere Priorität hat als in zsh--- Ich meine, der Befehl scheint als gelesen zu werden

(cd /tmp && echo A) & 

in bashund als

cd /tmp && (echo A &) 

in zsh. Ist das richtig oder ist die Ursache für das unterschiedliche Verhalten eine andere?

Rmano
quelle

Antworten:

9

Unterschiedliches, dokumentiertes Verhalten in zshmisc

Eine Liste ist eine Sequenz von null oder mehr Unterlisten, wobei jede Unterliste von beendet wird ;, &, &|, &!, oder eine neue Zeile. Dieser Terminator kann optional in der letzten Unterliste in der Liste weggelassen werden, wenn die Liste als komplexer Befehl in (...)oder angezeigt wird {...}. Wenn eine Unterliste durch ;oder newline beendet wird , wartet die Shell auf den Abschluss, bevor die nächste Unterliste ausgeführt wird. Wenn eine Unterliste durch ein &, &|oder beendet wird , führt &!die Shell die letzte darin enthaltene Pipeline im Hintergrund aus und wartet nicht darauf, dass sie beendet wird (beachten Sie den Unterschied zu anderen Shells, die die gesamte Unterliste im Hintergrund ausführen). Eine Pipeline im Hintergrund gibt den Status Null zurück.

llua
quelle
3

Eingegraben zshmisc(1)ist die folgende Zeile:

Wenn eine Unterliste durch ein &',& | 'oder `&!' Beendet wird , führt die Shell die letzte darin enthaltene Pipeline im Hintergrund aus.

Es wird zwar nicht ausdrücklich angegeben, dass die anderen Pipelines in der Unterliste in der aktuellen Shell ausgeführt werden, dies scheint jedoch zu implizieren, und das beobachtete Verhalten unterstützt diese Interpretation. Zum Beispiel:

$ echo $foo $bar

$ foo=3 && bar=5 && sleep 1 &
$ echo $foo $bar
3 5

unterstützt auch die Vorstellung, dass die ersten beiden Pipelines in der aktuellen Shell ausgeführt werden und nur die letzte Pipeline der Unterliste tatsächlich im Hintergrund ausgeführt wird.

chepner
quelle