13

Why is it that ssh -t doesn't wait for background jobs to finish?

Example:

ssh user@example 'sleep 2 &'

This works as expected, since ssh returns after 2 seconds, whereas

ssh user@example -t 'sleep 2 &'

does not wait for sleep to finish and returns immediately.

Can anyone explain the reason behind this? Is there a way to let ssh -t wait for all background processes to finish before returning?

My use case is that I start a script with ssh -t, and this script starts several background jobs that should stay alive after the main script finishes. With ssh -t this is not possible so far.

22

Without -t, sshd gets the stdout of the remote shell (and children like sleep) and stderr via two pipes (and also sends the client's input via another pipe).

sshd does wait for the process in which it has started the user's login shell, but also, after that process has terminated waits for eof on the stdout pipe (not the stderr pipe in the case of openssh at least).

And eof happens when there's no file descriptor by any process open on the writing end of the pipe, which typically only happens when all the processes that didn't have their stdout redirected to something else are gone.

When you use -t, sshd doesn't use pipes. Instead, all the interaction (stdin, stdout, stderr) with the remote shell and its children are done using one pseudo-terminal pair.

With a pseudo-terminal pair, for sshd interacting with the master side, there's no similar eof handling or any way to know if there are still processes with fds open to the slave side of the pseudo-terminal, so it just waits for the termination of the process in which it executed the login shell of the remote user and then exits.

Upon that exit, the master side of the pty pair is closed which means the pty is destroyed, so processes controlled by the slave will receive a SIGHUP (which by default would terminate them).

  • 1
    thanks for the thorough answer! another thing i'd like to know: do all background processes terminate once the pseudo terminal exits? the script i'm starting starts a service, which works well with ssh. but when using ssh -t, the service is not started. it seems that the service gets shut down once ssh returns. – Philipp Murry Feb 21 '17 at 14:59
  • Actually, there is a way for the master side of a pseudo-terminal to know when all slave file descriptors have been closed. It's the same mechanism triggered by a real terminal when all file descriptors to it have been closed, in fact. – JdeBP Feb 21 '17 at 15:32
  • 1
  • @JdeBP, would you care to expand? I'm not sure what you mean. AFAICT terminal emulators (xterm and gnome-terminal at least) don't care about processes still having fds opened to the slave when the process they executed the shell in dies – Stéphane Chazelas Feb 21 '17 at 16:43
  • @PhilippMurry You can use nohup to keep a script running like that. (You might also consider starting long-running jobs inside of tmux so you can monitor their progress interactively, but a log file works fine.) – jpaugh Feb 21 '17 at 17:27
5

Use wait:

ssh user@example -t 'sleep 2 & wait'

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.