Priorité de && vs & dans bash et zsh

9

En répondant à cette question, j'ai découvert une différence très drôle (et subtile) entre le comportement dans bashet zsh:

Dans 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

Comme vous pouvez le voir, l'exécution de l'alias xest effectuée dans un sous-shell et donc le répertoire actuel ne change pas.

Pas dans 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] % 

ici le répertoire est changé.

Il semble que le &in bashait une priorité différente de celle de zsh--- je veux dire, la commande semble être lue comme

(cd /tmp && echo A) & 

dans bashet comme

cd /tmp && (echo A &) 

dans zsh. Est-ce correct ou la cause du comportement différent en est-elle un autre?

Rmano
la source

Réponses:

9

Comportement différent et documenté dans zshmisc

Une liste est une séquence de zéro ou plusieurs sous - listes, dans lequel chaque sous - liste est terminé par ;, &, &|, &!, ou un saut de ligne. Ce terminateur peut éventuellement être omis de la dernière sous-liste de la liste lorsque la liste apparaît comme une commande complexe dans (...)ou {...}. Lorsqu'une sous-liste est terminée par ;ou newline, le shell attend qu'il se termine avant d'exécuter la sous-liste suivante. Si une sous ‐ liste se termine par un &,, &|ou &!, le shell exécute le dernier pipeline qu'il contient en arrière-plan et n'attend pas qu'il se termine (notez la différence avec les autres shells qui exécutent toute la sous-liste en arrière-plan). Un pipeline en arrière-plan renvoie un état de zéro.

llua
la source
3

Enterré zshmisc(1)est la ligne suivante:

Si une sous-liste se termine par un &',& | ', ou `&!', Le shell exécute le dernier pipeline qu'il contient en arrière-plan,

Bien qu'il ne précise pas spécifiquement que les autres pipelines de la sous-liste sont exécutés dans le shell actuel, cela semble être ce que cela implique, et le comportement que vous observez prend en charge cette interprétation. Par exemple:

$ echo $foo $bar

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

prend également en charge la notion selon laquelle les deux premiers pipelines s'exécutent dans le shell actuel, et seul le dernier pipeline de la sous-liste s'exécute réellement en arrière-plan.

chepner
la source