我试图编写Linux shell脚本(最好是bash),
据称名为detach.sh
,以便从终端安全地分离程序,
这样:
调用:./detach.sh prog [arg1 arg2 ...]
。
exec
能否,例如。在shell中运行它:
exec ./detach.sh prog [arg1 arg2 ...]
正确引用(主要处理包含空格的参数)。
丢弃输出(因为它们不需要)。
不使用screen
,tmux
等。
(与4相同的原因,加上不需要额外的保姆过程)。
使用(合理)便携式命令和程序,
而且start-stop-daemon
之类的东西并不是特定于发行版的。
我想到了几种方式(shebang lines #!/bin/bash
被忽略了
为了简洁起见):
nohup
:
nohup "$@" >& /dev/null &
disown
:
"$@" >& /dev/null &
disown
setsid
:
setsid "$@" >& /dev/null &
使用子shell:
("$@" >& /dev/null &)
nohup
/ setsid
结合了子shell:
# Or alternatively:
# (nohup "$@" >& /dev/null &)
(setsid "$@" >& /dev/null &)
使用gedit
作为测试程序(替换"$@"
部分)时,
条件1可满足上述所有方法,
但条件2可以不满足。
但是,如果将任意程序(但不是shell内置)附加到脚本5,
所有条件似乎都得到满足(至少在gedit
案例中对我来说)。
例如:
(setsid "$@" >& /dev/null &)
# Not just `true' because it is also a shell builtin.
/bin/true
任何想要解释上述现象的人 以及如何正确实施要求?
修改
对于条件2,我的意思是程序应该从终端分离但是照常运行。例如,对于gedit
情况,如果gedit
在脚本处理结束后立即退出,则条件将失败。
答案 0 :(得分:3)
经过仔细调查,这些以前未被注意的事实被揭露出来:
脚本3和5(仅setsid
变体)都将
如果脚本附加/bin/true
,则满足所有条件。
这些脚本,如事实1中修改的那样,如果可以的话
/bin/true
替换为for i in {0..9999}; do :; done
。
因此我们可以得出结论:
(来自事实1)
不需要多级分离(如脚本5),
关键是使用正确的实用程序(setsid
)。
(来自事实2)
在bash退出之前的适当延迟是脚本成功的必要条件。
(调用外部程序/bin/true
会消耗一些时间,
就像纯粹的bash时间消费者for i in {0..9999}; do :; done
一样。)
我没有查看源代码,但我想可能的解释
是bash可以在setsid
完成配置执行之前退出
如果没有适当的延迟,则运行程序的环境。
最后,最佳解决方案应该是
#!/bin/bash
setsid "$@" >& /dev/null &
sleep 0.01
编辑1 :
已经解释了延迟的必要性here。非常感谢@wilx!
编辑2 :
(感谢@MateiDavid)我们似乎忘记了重定向标准输入,更好的方法是:
#!/bin/bash
setsid "$@" >& /dev/null < /dev/null &
答案 1 :(得分:1)
我认为您需要执行setsid "$@" >& /dev/null & wait
,以便控制终端在setsid
设法分叉孩子之前不会消失。
<强>更新强>
在我看来,这既适用于命令行,也适用于-c
的参数:
(setsid tail -F /var/log/messages >& /dev/null) & disown
答案 2 :(得分:0)
您正在尝试创建UNIX守护程序进程(即,没有控制终端并且是其自己的session领导者的进程)。 setsid
命令应该为您执行此操作,但您负责关闭在您放弃的终端上打开的所有文件描述符。这可以通过将它们重定向到/dev/null
或使用shell的语法来关闭文件描述符(例如,Bash中的2>&-
和0<&-
)来完成。