(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.