(bash) Script A, wait for script B, but not its child process
The problem here is that sshd
waits for end-of-file on the pipe it is reading the command's stdout (not the stderr one for some reason, at least with the version I'm testing on) from. And the background job inherits a fd to that pipe.
So, to work around that, redirect the output of that background rsync
command to some file or /dev/null
if you don't care for it. You should also redirect stderr, because even if sshd is not waiting for the corresponding pipe, after sshd
exits, the pipe will be broken so rsync
would be killed if it tries to write on stderr.
So:
rsync ... > /dev/null 2>&1 &
Compare:
$ time ssh localhost 'sleep 2 &'
ssh localhost 'sleep 2 &' 0.05s user 0.00s system 2% cpu 2.365 total
$ time ssh localhost 'sleep 2 > /dev/null &'
ssh localhost 'sleep 2 > /dev/null &' 0.04s user 0.00s system 12% cpu 0.349 total
And:
$ ssh localhost '(sleep 1; ls /x; echo "$?" > out) > /dev/null &'; sleep 2; cat out
141 # ls by killed with SIGPIPE upon writing the error message
$ ssh localhost '(sleep 1; ls /x; echo "$?" > out) > /dev/null 2>&1 &'; sleep 2; cat out
2 # ls exited normally after writing the error on /dev/null instead
# of a broken pipe
Write a script which is the parent of both, then you can easily control both. Alternatively establish a communications channel between the two channels.
To specifically ignore certain background jobs you can capture the PID ($!
is the last backgrounded job PID) and wait $pid
to wait only for that job to complete.
The -f
flag to ssh
fixes the problem. Tested on:
#!/bin/sh -e
echo $$_script__begin
( echo sleeping; sleep 2; echo slept )&
echo $$_script__end
When I run it with ssh localhost ./script
, it waits until slept
shows up. With the -f
flag, it exits at echo $$_script__end
and slept
later shows up in the background after the ssh
command has returned.