9

Answering this question I discovered a very funny (and subtle) difference between behavior in bash and 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

As you can see, the execution of alias x is carried out in a subshell and so the current directory does not change.

Not 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] % 

here the directory is changed.

It seems that the & in bash has a different priority than in zsh --- I mean, the command seems to be read as

(cd /tmp && echo A) & 

in bash and as

cd /tmp && (echo A &) 

in zsh. Is this correct or the cause of the different behavior is another one?

9

Different, documented behavior in zshmisc

A list is a sequence of zero or more sublists, in which each sublist is terminated by ;, &, &|, &!, or a newline. This terminator may optionally be omitted from the last sublist in the list when the list appears as a complex command inside (...) or {...}. When a sublist is terminated by ; or newline, the shell waits for it to finish before executing the next sublist. If a sub‐list is terminated by a &, &|, or &!, the shell executes the last pipeline in it in the background, and does not wait for it to finish (note the difference from other shells which execute the whole sublist in the background). A backgrounded pipeline returns a status of zero.

| improve this answer | |
3

Buried in zshmisc(1) is the following line:

If a sublist is terminated by a &',&|', or `&!', the shell executes the last pipeline in it in the background,

While it doesn't specifically state that the other pipelines in the sublist are executed in the current shell, that does seem to be what it is implying, and the behavior you observe supports that interpretation. For example:

$ echo $foo $bar

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

also supports the notion at that the first two pipelines execute in the current shell, and only the last pipeline of the sublist actually executes in the background.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.