Cas*_*tor 9 bash shell scripting
我正在尝试编写一个Linux shell脚本(最好是命名为bash)detach.sh,以便安全地从终端分离程序,这样:
调用:./detach.sh prog [arg1 arg2 ...].
是exec-able,例如.通过在shell中运行它:
exec ./detach.sh prog [arg1 arg2 ...]
Run Code Online (Sandbox Code Playgroud)通过适当的引用(主要处理包含空格的参数).
丢弃输出(因为它们是不需要的).
不使用screen,tmux等等(与4相同的原因,加上不需要额外的保姆过程).
使用(合理地)可移植命令和程序,并且没有类似于start-stop-daemon特定于发行版的内容.
我想到了几种方法(#!/bin/bash为了简洁而忽略了shebang线):
nohup:
nohup "$@" >& /dev/null &
Run Code Online (Sandbox Code Playgroud)disown:
"$@" >& /dev/null &
disown
Run Code Online (Sandbox Code Playgroud)setsid:
setsid "$@" >& /dev/null &
Run Code Online (Sandbox Code Playgroud)使用子shell:
("$@" >& /dev/null &)
Run Code Online (Sandbox Code Playgroud)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在脚本处理结束后立即退出,则条件失败.
经过仔细调查,这些以前未被注意到的事实被揭露:
如果将 a 附加到脚本,则脚本 3 和 5(setsid仅变体)都将满足所有条件。/bin/true
/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)