When writing a Linux shell script to safely disconnect programs from the terminal

I am trying to write a Linux shell script (preferably bash), supposedly called detach.sh , to safely disconnect programs from the terminal, such that:

  • Call: ./detach.sh prog [arg1 arg2 ...] .

  • Is exec -able, for example. running this in its shell:

     exec ./detach.sh prog [arg1 arg2 ...] 
  • With proper quoting (mostly handling arguments containing spaces).

  • Discards exits (since they are not needed).

  • Does not use screen , tmux , etc. (for the same reason with 4, plus there is no need for an additional babysitting process).

  • It uses (reasonably) portable commands and programs, and there are no such things as start-stop-daemon , which is quite specific to the distribution.

I thought of several ways (the shebang lines #!/bin/bash neglected for brevity):

  • nohup :

     nohup "$@" >& /dev/null & 
  • disown :

     "$@" >& /dev/null & disown 
  • setsid :

     setsid "$@" >& /dev/null & 
  • Using a subshell:

     ("$@" >& /dev/null &) 
  • nohup / setsid in combination with a subshell:

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

When using gedit as a test program (substituting the "$@" ), condition 1 can be satisfied by all the above methods, but condition 2 cannot be satisfied by anything.

However, if an arbitrary program (but not a built-in shell) is added to script 5, all the conditions seem to be satisfied (at least for me in the case of gedit ). For example:

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

Anyone who has an idea of ​​explaining the above phenomena and how to properly fulfill the requirements?

EDIT:

With condition 2, I mean that the program must be disconnected from the terminal, but it works as usual otherwise. For example, in the case of gedit condition is not met if gedit just exits immediately after the script process completes.

+9
scripting bash shell
Apr 20 2018-12-12T00:
source share
3 answers

Upon closer inspection, these previously inconspicuous facts were discovered:

  • Both scripts 3 and 5 (only the setsid option) will satisfy all conditions if a /bin/true added to the script.

  • These scripts, as modified by actually 1, will work if /bin/true is replaced by for i in {0..9999}; do :; done for i in {0..9999}; do :; done for i in {0..9999}; do :; done .

Therefore, we can conclude that:

  • (From fact 1)

    Several disconnect levels (as in script 5) are not needed, and the key must use the correct utility ( setsid ).

  • (From fact 2)

    For the script to succeed, a suitable delay is required until bash exits. (Calling the external program /bin/true takes some time, just like the consumer for i in {0..9999}; do :; done time <- → <.>

    I didn’t look at the source code, but I think a possible explanation is that bash can exit before setsid completes the runtime setup if the corresponding delay is not applied.

And finally, the optimal solution should be

 #!/bin/bash setsid "$@" >& /dev/null & sleep 0.01 

EDIT 1 :

The need for delay has been explained here. Thanks a lot @wilx!

EDIT 2 :

(Thanks to @MateiDavid) we seem to have forgotten to redirect standard input, and the best way:

 #!/bin/bash setsid "$@" >& /dev/null < /dev/null & 
+3
Mar 30 '14 at 8:08
source share

I think you need to do setsid "$@" >& /dev/null & wait so that the control terminal does not disappear before setsid can unlock the child.

UPDATE

It seems to me that this works both on the command line and as an argument to -c :

 (setsid tail -F /var/log/messages >& /dev/null) & disown 
+1
May 10 '16 at 9:46 a.m.
source share

You are trying to create a UNIX daemon process (i.e. a process that does not have a control terminal, and this is its own session ). The setsid command should do this for you, but you are responsible for closing all file descriptors opened on the terminal that you are leaving. This can be done by redirecting them to /dev/null or using shell syntax to close file descriptors (for example, 2>&- and 0<&- in Bash).

0
May 01 '12 at 19:15
source share



All Articles