Shell – How to Detach a Process from Sh or ‘Disown’ for Sh

disownprocess-managementshell

Consider a shell script executed by Sh, not Bash (and I can't change it, and can't use a shebang, it's ignored). The & operator works, but disown $! does not and makes Sh complains “disown: not found”.

How do I detach a background process from specifically Sh? I mean, doing from Sh the same as disown do from Bash.

Best Answer

First let's see what Bash's disown command does. From Bash manual:

The shell exits by default upon receipt of a SIGHUP. Before exiting, an interactive shell resends the SIGHUP to all jobs, running or stopped. Stopped jobs are sent SIGCONT to ensure that they receive the SIGHUP. To prevent the shell from sending the SIGHUP signal to a particular job, it should be removed from the jobs table with the disown builtin (see Job Control Builtins) or marked to not receive SIGHUP using disown -h.

If the huponexit shell option has been set with shopt (see The Shopt Builtin), Bash sends a SIGHUP to all jobs when an interactive login shell exits.

What this means is that it's the shell itself, if it receives SIGHUP, forwards it to the background jobs. If the shell exits (and huponexit had't been enabled), the background processes—which don't have a controlling terminal—don't get SIGHUP on terminal closing.

So if your concern is to prevent SIGHUP to a process launched from a shell wrapper, like e.g.

#!/bin/sh
my-command arg &

then there's no need in disown-like functionality, since my-command will not receive SIGHUP unless the shell gets it before exiting.

But, there still is a problem if you want to run a child from a script that will continue execution for some time after launching the child, like e.g. here:

#!/bin/sh
sleep 55555 &
sleep 3333 # some long operation we don't care about

The script above will terminate the sleep 55555 command if the script's controlling terminal closes. Since Bourne shell doesn't have the disown builtin that Bash, Ksh and some other shells have, we need another tool. That tool is nohup(1). The above script, in which we aren't interested in the stdout and stderr of the child process, can be modified to the following to avoid sleep getting SIGHUP:

#!/bin/sh
nohup sleep 55555 >/dev/null 2>&1 &
sleep 3333 # some long operation we don't care about

The redirection to /dev/null is to avoid getting the nohup.out file in current directory. Without the redirection, this file will contain the output of the nohupped process.

Related Question