Bash 编写Linux shell脚本以安全地从终端分离程序
我正在尝试编写一个Linux shell脚本(最好是bash), 假定命名为Bash 编写Linux shell脚本以安全地从终端分离程序,bash,shell,scripting,Bash,Shell,Scripting,我正在尝试编写一个Linux shell脚本(最好是bash), 假定命名为detach.sh,用于安全地从终端分离程序, 以便: 调用:/detach.sh prog[arg1 arg2…] exec-可执行,例如,通过在shell中运行此命令: exec ./detach.sh prog [arg1 arg2 ...] 正确引用(主要处理包含空格的参数) 丢弃输出(因为它们是不需要的) 不使用屏幕,tmux等。 (与4相同的原因,再加上不需要额外的保姆程序) 使用(合理)可移植的命令和程
detach.sh
,用于安全地从终端分离程序,
以便:
/detach.sh prog[arg1 arg2…]
exec
-可执行,例如,通过在shell中运行此命令:
exec ./detach.sh prog [arg1 arg2 ...]
屏幕
,tmux
等。
(与4相同的原因,再加上不需要额外的保姆程序)#!/bin/bash
)
为了简洁起见):
nohup
:
nohup "$@" >& /dev/null &
disown
:
"$@" >& /dev/null &
disown
setsid
:
setsid "$@" >& /dev/null &
("$@" >& /dev/null &)
# Or alternatively:
# (nohup "$@" >& /dev/null &)
(setsid "$@" >& /dev/null &)
nohup
/setsid
与子shell组合:
("$@" >& /dev/null &)
# Or alternatively:
# (nohup "$@" >& /dev/null &)
(setsid "$@" >& /dev/null &)
gedit
作为测试程序时(替换“$@”
部分),
上述所有方法均可满足条件1,
但条件2不能满足任何条件
但是,如果脚本5中附加了任意程序(但不是shell内置程序),
所有条件似乎都得到了满足(至少对我来说,在gedit
案例中是这样)。
例如:
(setsid "$@" >& /dev/null &)
# Not just `true' because it is also a shell builtin.
/bin/true
有人对上述现象的解释有想法吗
如何正确实施这些要求
编辑:
对于条件2,我的意思是程序应该与终端分离,但在其他情况下运行正常。例如,在
gedit
情况下,如果gedit
在脚本进程结束后立即退出,则该条件将失败。您正在尝试创建一个UNIX守护进程(即,一个没有控制终端的进程,它是自己的领导者)。setsid
命令应该为您执行此操作,但您有责任关闭在要放弃的终端上打开的所有文件描述符。这可以通过将它们重定向到/dev/null
或使用shell的语法关闭文件描述符(例如,2>&-
和0)来实现。经过更仔细的调查,发现了这些以前未被注意到的事实:
脚本3和5(仅限setsid
变体)都将
如果脚本中附加了/bin/true
,则满足所有条件
这些脚本,如事实1中所修改的,如果
/bin/true
被{0..9999};do:;done
中的i替换为
因此,我们可以得出结论:
- (来自事实1)
不需要多级分离(如脚本5所示),
关键是使用正确的实用程序(
setsid
)
- (来自事实2)
bash退出之前的适当延迟对于脚本的成功是必要的。
(调用外部程序
/bin/true
需要花费一些时间,
就像{0..9999}中i的纯bash时间消费者;do:;done
)
我没有看过源代码,但我想可能有一个解释
bash可能在setsid
完成配置执行之前退出
如果未应用适当的延迟,则运行程序的环境
最后,一个最优的解决方案应该是
#!/bin/bash
setsid "$@" >& /dev/null &
sleep 0.01
编辑1:
已经解释了延迟的必要性。非常感谢@wilx
编辑2:
(感谢@MateiDavid)我们似乎忘记了重定向标准输入,更好的方法是:
#!/bin/bash
setsid "$@" >& /dev/null < /dev/null &
!/bin/bash
setsid“$@”>&/dev/null
我认为您需要执行setsid“$@”>和/dev/null&wait
,以便在setsid
设法分叉孩子之前,控制终端不会消失
更新
在我看来,这既适用于命令行,也适用于-c
的参数:
(setsid tail -F /var/log/messages >& /dev/null) & disown
假设您拥有shebang,那么解决方案5在哪些方面不满足要求2?或者,近似地说,解决方案5不满足要求2意味着什么?当gedit
在后台运行时,您预计会发生什么情况?因为gedit
是一个交互式运行的编辑器,但后台进程是可用的,或多或少,根据定义,一些在没有用户交互的情况下运行的东西,可能问题在于您选择的测试程序。处理基于X11的程序与处理编译器之类的程序有很大的不同。当您在后台运行gedit
时,您看到了什么情况?很抱歉对我的想法进行了不正确的解释。我的意思是在说“背景”时使用“分离”。请查看此问题的更新版本。感谢您的帮助:)字符串“shebang lines#/bin/bash
忽略了为StackExchange的服务器节省磁盘空间“占用的磁盘空间比实际的Shebang多。@Pumbaa80:也许原因应该是“为了简洁”:)谢谢,但我认为脚本3和5(请参阅我的问题)我已经做了这两件事,但仍然没有解决问题。此外,调用/bin/true
左右解决问题的现象的原因仍然无法解释。非常感谢:)我更新了我自己的答案以反映您的建议。解释非常合理。但是bash-c'setsid sleep 1>和/dev/null&wait'
以某种方式阻塞(虽然它在interactivebash
中没有阻塞),因此目前还不能解决问题。但是$exec bash-c'(setId geany>&/dev/null)&disown'
失败;我认为最好看看为什么setId
'd进程的PID与setId
不同