After trying to figure out why a Capistrano task (which tried to start a daemon in the background) was hanging, I discovered that using && in bash over ssh prevents a subsequent program from running in the background. I tried it on bash 4.1.5 and 4.2.20.
The following will hang (i.e. wait for sleep to finish) in bash:
ssh localhost "cd /tmp && nohup sleep 10 >/dev/null 2>&1 &"
The following won’t:
ssh localhost "cd /tmp ; nohup sleep 10 >/dev/null 2>&1 &"
Neither will this:
cd /tmp && nohup sleep 10 >/dev/null 2>&1 &
Both zsh and dash will execute it in the background in all cases, regardless of && and ssh. Is this normal/expected behavior for bash, or a bug?
One easy solution is to use:
(this also works if you use braces, see second example below).
I did not experiment further but I am reasonably convinced it has to do with open file descriptors hanging around. Perhaps zsh and dash bind the
&&so that this means what has to be spelled as:in bash.
Nope, quick experiment in dash shows that
echo foo && echo bar >fileonly redirects the latter. Still, it has to have something to do with lingering open fd’s causing ssh to wait for more output; I’ve run into this a lot in the past.One more trick, not needed if you use the parentheses or braces for this particular case but might be useful in a more general context, where the set of commands to do with
&&are more complex. Since bash seems to be hanging on to the file descriptor inappropriately with&&but not with;, you can turna && b && cintoa || exit 1; b || exit 1; c. This works with the test case:Replace
truewithfalseand the echo of “going on” is omitted.(You can also
set -e, although sometimes that is a bigger hammer than desired.)