Casper Ti. Vector Casper Ti. Vector - 5 months ago 20
Bash Question

On writing a Linux shell script to safely detach programs from a terminal

I'm trying to write a Linux shell script (preferably bash),
supposedly named
, to safely detach programs from a terminal,
such that:

  1. Invocation:
    ./ prog [arg1 arg2 ...]

  2. Is
    -able, eg. by running this in your shell:

    exec ./ prog [arg1 arg2 ...]

  3. With proper quoting (mainly handling of arguments containing whitespaces).

  4. Discards the outputs (since they are unneeded).

  5. Does not use
    , etc.
    (same reason with 4, plus no need for an extra babysitting process).

  6. Uses (reasonably) portable commands and programs,
    and no things like
    which is quite distro-specific.

I have thought of several ways (shebang lines
for the sake of briefness):

  1. nohup

    nohup "$@" >& /dev/null &

  2. disown

    "$@" >& /dev/null &

  3. setsid

    setsid "$@" >& /dev/null &

  4. Using a subshell:

    ("$@" >& /dev/null &)

  5. nohup
    combined with subshell:

    # Or alternatively:
    # (nohup "$@" >& /dev/null &)
    (setsid "$@" >& /dev/null &)

When using
as the test program (substituting the
condition 1 can be satisfied with all the above methods,
but condition 2 can be satisfied with none.

However, if an arbitrary program (but not a shell builtin) is appended to script 5,
all the conditions seem to be satisfied (at least for me in the
For example:

(setsid "$@" >& /dev/null &)
# Not just `true' because it is also a shell builtin.

Anyone with an idea about an explanation of the above phenomenons
and how to correctly implement the requirements?


With condition 2, I mean the program should be detached from the terminal but runs as usual otherwise. For example, with the
case, the condition fails if
just exits immediately right after the process of the script has ended.


Upon closer investigation, these previously unnoticed facts were revealed:

  1. Both scripts 3 and 5 (the setsid variant only) will satisfy all the conditions if a /bin/true is appended to the script.

  2. These scripts, as modified in fact 1, will work as well if /bin/true is replaced with for i in {0..9999}; do :; done.

Therefore we can conclude that:

  • (From fact 1)

    Multiple levels of detaching (as in script 5) is unnecessary, and the key is to use the right utility (setsid).

  • (From fact 2)

    A suitable delay before bash exit is necessary for the success of the script. (Calling external program /bin/true consumes some time, just like the pure-bash time consumer for i in {0..9999}; do :; done.)

    I have not looked at the source code, but I guess a possible explanation is that bash may exit before setsid finishes configuring the execution environment of the program to run, if an appropriate delay is not applied.

And finally, an optimal solution should be

setsid "$@" >& /dev/null &
sleep 0.01