When running a long-running command in the background over SSH from a non-interactive shell script, I noticed the process continues running on the remote machine without using nohup, disown, or similar tools.
Remote Environment (SSH target):
- Linux 6.12.9
- OpenSSH 9.9p1, OpenSSL 3.3.2
- Login Shell: bash 5.2.37
- Also for non-interactive sessions (verified by
ssh -T $HOST "echo \$SHELL")
- Also for non-interactive sessions (verified by
- Distribution: NixOS 24.11
On the client side, I can execute:
# Closing outgoing FDs (stdout and stderr) important to end # SSH session immediately (EOF). We also need a non-interactive # session (-T). ssh -T $HOST "long_running_command >/dev/null 2>/dev/null &" to start a long running command on the remote without having to keep the SSH session alive.
I expected that background jobs would terminate or receive SIGHUP when the SSH session ends. However, the process is automatically reparented to PID 1 (init) and keeps running. I can verify this using htop, ps, et. al.
Why does this work without nohup or disown?
- Why does it just work like that? Why are no
SIGHUPor similar events being send tolong_running_command? - Why does job control (
&) work in bash in non-interactive mode? - Who decides that the running background job will switch ownership to the init process? Bash? Is this documented?
nohupdoes (it's not magic).