【问题标题】:How do I write a watchdog daemon in bash?如何在 bash 中编写看门狗守护进程?
【发布时间】:2012-08-15 01:58:57
【问题描述】:

我想要一种在 shell 脚本中编写守护程序的方法,它会在循环中运行另一个应用程序,如果它死了就重新启动它。

  • 当在 SSH 会话中使用 ./myscript.sh 运行时,它将启动一个新的守护进程实例,除非该守护进程已经在运行。
  • 当 SSH 会话结束时,守护进程将继续存在。
  • 应该有一个参数 (./myscript -stop) 可以杀死任何现有的守护进程。

(关于编辑的注意事项 - 原始问题指定不能使用nohup 和类似工具。这个人为的要求是“XY 问题”,并且接受的答案实际上使用了 OP 声称无法使用的所有工具。)

【问题讨论】:

  • 为什么需要 pid?这听起来有点可疑:要拥有一个守护进程,您需要使用双分叉技巧(fork/setsid/fork)。这意味着启动进程虽然可以将孙子进程的 pid 发送给它,但不能等待守护进程。守护进程的 pid 并没有太多用处(当然,守护进程本身可以使用它,例如放入 /var/run 并确保它是自身运行的唯一副本)。
  • @NicholasWilson 如果我们在那个技巧中得到的 PID 没有用,你能给我一个你说的版本的例子吗?因为我前段时间看到过那个技巧,现在记不起很多细节了。我需要 PID 来避免重复。过程。所以主进程将接收诸如启动、停止等参数,并且分叉应该作为那里的另一个进程的看门狗。我对看门狗和 args 没有问题,但坚持正确的分叉
  • 您必须再解释一下。你说你想要一个守护进程,也就是说,一个完全脱离启动它的进程。您需要另一个可以控制守护程序的脚本。您是否要避免重复的守护进程?在这种情况下,在您的守护程序脚本开始时您应该执行if test -f /var/run/appname.pid; then exit; fi; echo $$ > /var/run/appname.pid; trap 'rm /var/run/appname.pid' EXIT。然后使用 nohup 启动守护进程。要与守护进程通信,无论如何您都需要使用其他一些 IPC 机制(bash 支持 FIFO)。
  • @NicholasWilson 所以这个脚本的一般目的是它会被调用让我们说从像 ./my_script.sh 这样的 ssh 会话然后它将自己分叉到守护进程,作为守护进程它将启动另一个appname,然后在无限循环中运行,每秒检查该进程是否处于活动状态,如果没有 - 重新启动它。正如我之前提到的,我非常了解 nohup,但在我的情况下它没有用,就像没有可用的 cron 一样。
  • 还有一点,为什么不能使用 nohup 来调用这个脚本本身:这个脚本是从另一个脚本调用的,并检查它是否已经在运行,如果没有,那么它进入守护进程,如果是,它退出让守护程序运行并报告这种情况,如果使用参数调用顶级脚本让我们说停止——它将能够停止这个看门狗。

标签: bash shell daemon nohup


【解决方案1】:

根据 cmets 中的说明,您真正想要的是一个守护进程,它可以让子进程保持运行,并在它退出时重新启动它。您想要一种在 ssh 会话中键入“./myscript.sh”并启动守护进程的方法。

#!/usr/bin/env bash
PIDFILE=~/.mydaemon.pid
if [ x"$1" = x-daemon ]; then
  if test -f "$PIDFILE"; then exit; fi
  echo $$ > "$PIDFILE"
  trap "rm '$PIDFILE'" EXIT SIGTERM
  while true; do
    #launch your app here
    /usr/bin/server-or-whatever &
    wait # needed for trap to work
  done
elif [ x"$1" = x-stop ]; then
  kill `cat "$PIDFILE"`
else
  nohup "$0" -daemon
fi

运行脚本:它将使用 nohup 为您启动守护进程。守护进程是一个循环,监视子进程退出,并在退出时重新启动它。

为了控制守护进程,脚本可以使用-stop 参数来杀死守护进程。查看系统初始化脚本中的示例以获得更完整的示例以及更好的错误检查。

【讨论】:

    【解决方案2】:

    最近“后台”进程的pid存储在$!

    $ cat &
    [1] 7057
    $ echo $!
    7057
    

    我不知道 bash 中有 fork 命令。你确定 bash 是适合这项工作的工具吗?

    【讨论】:

    • 是的,我确定。并且获取last run proccess的PID是没有问题的,但是和fork不一样。 fork 的目的是能够创建一个守护进程,在父进程挂掉后不会死掉。当调用者挂断时(例如,您从 ssh 会话中注销),使用 bg 或 &(它们相同)运行 proc 将不会让它继续运行
    • @AlexKey 如果你想在挂断 ssh 连接时让进程继续运行,你需要做两件事。 1. 取消进程,因此当 shell 死亡时它不会得到 SIGHUP,以及 2. 重定向所有输入和输出,否则 ssh 可能会挂起等待输入/输出关闭。因此:cmd </dev/null >/dev/null 2>&1 & disown
    • @geirha 是的,我知道它在理论上是如何工作的,例如可以在 C++ 中实现它。但是当谈到 bash 脚本时,我经常会遇到这种事情。你能给我这个代码示例吗?我试图用谷歌搜索 bash fork 示例,但一切都指向 nohup,这对我来说没用。
    • @AlexKey,我做到了:cmd </dev/null >/dev/null 2>&1 & disown
    猜你喜欢
    • 2016-08-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-25
    相关资源
    最近更新 更多