编写Linux shell脚本以安全地从终端分离程序

Cas*_*tor 9 bash shell scripting

我正在尝试编写一个Linux shell脚本(最好是命名为bash)detach.sh,以便安全地从终端分离程序,这样:

  1. 调用:./detach.sh prog [arg1 arg2 ...].

  2. exec-able,例如.通过在shell中运行它:

    exec ./detach.sh prog [arg1 arg2 ...]
    
    Run Code Online (Sandbox Code Playgroud)
  3. 通过适当的引用(主要处理包含空格的参数).

  4. 丢弃输出(因为它们是不需要的).

  5. 不使用screen,tmux等等(与4相同的原因,加上不需要额外的保姆过程).

  6. 使用(合理地)可移植命令和程序,并且没有类似于start-stop-daemon特定于发行版的内容.

我想到了几种方法(#!/bin/bash为了简洁而忽略了shebang线):

  1. nohup:

    nohup "$@" >& /dev/null &
    
    Run Code Online (Sandbox Code Playgroud)
  2. disown:

    "$@" >& /dev/null &
    disown
    
    Run Code Online (Sandbox Code Playgroud)
  3. setsid:

    setsid "$@" >& /dev/null &
    
    Run Code Online (Sandbox Code Playgroud)
  4. 使用子shell:

    ("$@" >& /dev/null &)
    
    Run Code Online (Sandbox Code Playgroud)
  5. nohup/ setsid结合子壳:

    # Or alternatively:
    # (nohup "$@" >& /dev/null &)
    (setsid "$@" >& /dev/null &)
    
    Run Code Online (Sandbox Code Playgroud)

gedit用作测试程序(代替该"$@"部分)时,可以用所有上述方法满足条件1,但是条件2可以不满足.

但是,如果将任意程序(但不是shell内置)附加到脚本5,则所有条件似乎都得到满足(至少在我的gedit情况下对我来说).例如:

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

任何人都对上述现象的解释以及如何正确实施要求有所了解?

编辑:

对于条件2,我的意思是该程序应该从终端分离但是照常运行.例如,对于这种gedit情况,如果gedit在脚本处理结束后立即退出,则条件失败.

Cas*_*tor 5

经过仔细调查,这些以前未被注意到的事实被揭露:

  1. 如果将 a 附加到脚本,则脚本 3 和 5(setsid仅变体)都将满足所有条件。/bin/true

  2. /bin/true这些脚本(如事实 1 中所修改)如果替换为也可以正常工作 for i in {0..9999}; do :; done

因此我们可以得出结论:

  • (来自事实1)

    多级分离(如脚本 5 所示)是不必要的,关键是使用正确的实用程序 ( setsid)。

  • (来自事实2)

    为了脚本的成功,在 bash 退出之前有适当的延迟是必要的。(调用外部程序/bin/true会消耗一些时间,就像pure-bash时间消耗一样for i in {0..9999}; do :; done。)

    我没有查看源代码,但我猜想一个可能的解释是,setsid如果不应用适当的延迟,bash 可能会在完成配置要运行的程序的执行环境之前退出。

最后,最佳解决方案应该是

#!/bin/bash
setsid "$@" >& /dev/null &
sleep 0.01
Run Code Online (Sandbox Code Playgroud)

编辑1

这里已经解释了延迟的必要性。非常感谢@wilx!

编辑2

(感谢@MateiDavid)我们似乎忘记了重定向标准输入,更好的方法是:

#!/bin/bash
setsid "$@" >& /dev/null < /dev/null &
Run Code Online (Sandbox Code Playgroud)