Precedencia de && vs & en bash y zsh

9

Respondiendo a esta pregunta descubrí una diferencia muy divertida (y sutil) entre el comportamiento en bashy zsh:

En 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

Como puede ver, la ejecución del alias xse lleva a cabo en una subshell y, por lo tanto, el directorio actual no cambia.

No en 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] % 

Aquí se cambia el directorio.

Parece que el &in bashtiene una prioridad diferente que en zsh--- Quiero decir, el comando parece leerse como

(cd /tmp && echo A) & 

en bashy como

cd /tmp && (echo A &) 

en zsh. ¿Es esto correcto o la causa del comportamiento diferente es otra?

Rmano
fuente

Respuestas:

9

Comportamiento diferente y documentado en zshmisc

Una lista es una secuencia de cero o más sublistas, en el que cada sublista se termina mediante ;, &, &|, &!, o un salto de línea. Este terminador se puede omitir opcionalmente de la última sublista en la lista cuando la lista aparece como un comando complejo dentro (...)o {...}. Cuando una sublista finaliza por ;o nueva línea, el shell espera a que termine antes de ejecutar la siguiente sublista. Si una sublista se termina por una &, &|o &!, el shell ejecuta la última tubería en ella, en el fondo, y no espera a que termine (tenga en cuenta la diferencia de otros proyectiles que ejecutan toda la lista secundaria en el fondo). Una tubería de fondo devuelve un estado de cero.

llua
fuente
3

Enterrado zshmisc(1)es la siguiente línea:

Si una sublista termina con un &',& | 'o `&!', El shell ejecuta la última canalización en el fondo,

Si bien no indica específicamente que las otras canalizaciones en la sublista se ejecutan en el shell actual, eso parece ser lo que está implicando, y el comportamiento que observa respalda esa interpretación. Por ejemplo:

$ echo $foo $bar

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

también admite la noción de que las dos primeras canalizaciones se ejecutan en el shell actual, y solo la última canalización de la sublista se ejecuta realmente en segundo plano.

chepner
fuente