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

标签 bash shell scripting

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

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

  2. exec 是否可用,例如。通过在你的 shell 中运行它:

    exec ./detach.sh prog [arg1 arg2 ...]
    
  3. 使用适当的引号(主要处理包含空格的参数)。

  4. 丢弃输出(因为不需要)。

  5. 不使用screentmux等。 (与 4 相同的原因,而且不需要额外的保姆过程)。

  6. (合理地)使用可移植的命令和程序, 并且没有像 start-stop-daemon 这样的发行版特定的东西。

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

  1. nohup:

    nohup "$@" >& /dev/null &
    
  2. 否认:

    "$@" >& /dev/null &
    disown
    
  3. setsid:

    setsid "$@" >& /dev/null &
    
  4. 使用子 shell:

    ("$@" >& /dev/null &)
    
  5. 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 在脚本进程结束后立即退出,则条件失败。

最佳答案

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

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

  2. 这些脚本在事实 1 中进行了修改,如果 /bin/true 替换为 for i in {0..9999};做 :;完成

因此我们可以得出结论:

  • (来自事实 1)

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

  • (来自事实 2)

    bash 退出之前的适当延迟对于脚本的成功是必要的。 (调用外部程序/bin/true会消耗一些时间, 就像纯 bash 时间消费者 for i in {0..9999};做 :;完成。)

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

最后,一个最优解应该是

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

编辑 1:

已经解释了延迟的必要性here .非常感谢@wilx!

编辑 2:

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

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

关于bash - 编写 Linux shell 脚本以安全地从终端分离程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10247721/

相关文章:

bash - 如何在没有进一步用户交互的情况下使用 sudo 在单独的终端中运行命令

linux - 定期将 bash 历史推送到 github

bash - 使用bash和sed如何从主机名命令中提取ip并将其保存在/etc/hosts文件中

bash - 为什么我得到 "syntax error near unexpected token ` (' "?

linux - 期望脚本调用另一个期望脚本

linux - 从右边提取两个/之间的字符串

javascript - 以编程方式在高度冲突的环境中包含 JQuery -

linux - Linux 终端中的 For 循环

ruby - 当 shell 环境不存在时,如何使用 RVM 从特定的 Ruby 版本运行 "bundle exec"

linux - 连接到 Linux 服务器并复制文件时将用户更改为 root