Precedência de && vs & no bash e zsh

9

Respondendo a essa pergunta , descobri uma diferença muito engraçada (e sutil) entre comportamento bashe zsh:

Em 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 você pode ver, a execução do alias xé realizada em um subshell e, portanto, o diretório atual não muda.

Não está em 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] % 

aqui o diretório é alterado.

Parece que o &in bashtem uma prioridade diferente do que em zsh--- quero dizer, o comando parece ser lido como

(cd /tmp && echo A) & 

dentro bashe como

cd /tmp && (echo A &) 

no zsh. Isso está correto ou a causa do comportamento diferente é outra?

Rmano
fonte

Respostas:

9

Comportamento documentado diferente zshmisc

Uma lista é uma sequência de zero ou mais sub-listas, em que cada sub-lista é terminada por ;, &, &|, &!, ou uma nova linha. Opcionalmente, esse terminador pode ser omitido da última sub-lista da lista quando a lista aparecer como um comando complexo dentro (...)ou {...}. Quando uma sublist é terminada por ;ou nova linha, o shell aguarda o término antes de executar a próxima sublist. Se uma sub-lista é terminada por um &, &|ou &!, o shell executa o último gasoduto nele no fundo, e não esperar que ela termine (note a diferença de outras conchas que executam toda a sub-lista em segundo plano). Um pipeline em segundo plano retorna um status zero.

llua
fonte
3

Enterrado zshmisc(1)é a seguinte linha:

Se uma sublist for terminada com um &',& | ', ou `&!', O shell executará o último pipeline no fundo,

Embora não indique especificamente que os outros pipelines da sublist são executados no shell atual, isso parece ser o que está implicando, e o comportamento que você observa suporta essa interpretação. Por exemplo:

$ echo $foo $bar

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

também suporta a noção de que os dois primeiros pipelines são executados no shell atual e apenas o último pipeline da sublist é realmente executado em segundo plano.

chepner
fonte