【问题标题】:bash restart sub-process using trap SIGCHLD?bash 使用陷阱 SIGCHLD 重新启动子进程?
【发布时间】:2023-03-13 08:31:01
【问题描述】:

我已经看到监视程序在脚本中使用“ps”或“服务状态(在 Linux 上)”定期检查进程状态,或者在 C/C++ 中分叉并等待进程...

我想知道是否可以使用带有陷阱的bash并在收到SIGCLD时重新启动子进程?

我已经按照以下想法在 RedHat Linux 上测试了一个基本套件(当然它没有工作......)

#!/bin/bash
set -o monitor # can someone explain this? discussion on Internet say this is needed
trap startProcess SIGCHLD
startProcess() { 
  /path/to/another/bash/script.sh & # the one to restart
  while [ 1 ]
  do
    sleep 60
  done
}
startProcess

正在启动的 bash 脚本只是休眠几秒钟然后退出。

观察到几个问题:

  • 当shell 在前台启动时,SIGCHLD 将只被处理一次。陷阱复位信号处理是否像信号()?
  • 脚本及其子脚本似乎对 SIGINT 免疫,这意味着它们不能被 ^C 阻止
  • 由于无法关闭,我关闭了终端。剧本好像是HUP,还剩下很多僵尸孩子。
  • 在后台运行时,脚本导致终端死机

...无论如何,这根本不起作用。我不得不说我对这个话题知之甚少。 有人可以建议或给出一些工作示例吗? 有没有这种用途的脚本?

那么在 bash 中使用 wait 怎么样?

谢谢

【问题讨论】:

    标签: bash child-process bash-trap sigchld


    【解决方案1】:

    我可以尝试回答您的一些问题,但不是全部基于我的内容 知道。

    1. set -o monitor(或等效的set -m)行开启工作 控件,默认情况下仅对交互式 shell 启用。这似乎 需要发送 SIGCHLD。然而,工作控制更多的是 一种交互功能,并不真正打算在 shell 脚本中使用 (另见this question)。

      另外请记住,这可能不是您打算做的 因为一旦您启用作业控制,将为每个发送 SIGCHLD 存在的外部命令(例如,每次运行 lsgrep 或 任何东西,当该命令完成并且您的陷阱时,将触发 SIGCHLD 将运行)。

    2. 我怀疑 SIGCHLD 陷阱只运行一次的原因是 因为您的陷阱处理程序包含一个前台无限循环,所以您的 脚本卡在陷阱处理程序中。似乎没有意义 无论如何都到那个循环,所以你可以简单地删除它。

    3. 脚本对 SIGINT 的“免疫”似乎是启用 作业控制(监控部分)。我的预感是开启工作控制, 运行脚本的 bash 子实例不再终止 自己响应 SIGINT 而是将 SIGINT 传递给 它的前台子进程。在您的脚本中,^C 即 SIGINT 就像其他编程语言中的 continue 语句一样 情况下,因为 SIGINT 只会杀死当前正在运行的sleep 60, 于是while循环将立即运行一个新的sleep 60

    4. 当我尝试运行您的脚本然后将其杀死时(来自另一个 终端),我最终得到的只是两个杂散的睡眠过程。

    5. 后台运行该脚本也会为我杀死我的 shell,虽然 行为不是非常一致(有时会发生 立即,其他时候根本没有)。似乎在键入其他任何键 比 enter 会导致 EOF 以某种方式发送。即使在终端之后 exits 脚本继续在后台运行。我不知道 这是怎么回事。

    更具体地说明您想要完成的工作会有所帮助。如果 你只想要一个命令在你的生命周期内连续运行 脚本,你可以在后台运行一个无限循环,比如

    while true; do
        some-command
        echo some-command finished
        echo restarting some-command ...
    done &
    

    注意done 后面的&

    对于其他任务,wait 可能比使用作业控制更好 在 shell 脚本中。同样,这取决于您到底在尝试什么 去做。

    【讨论】:

    • 感谢 Jimmy 的分享,甚至测试了糟糕的脚本。我已经停止了尝试,使用“传统”方式来做——循环和检查。但是,我测试了“等待”,它在基本场景中确实非常有效。 #!/bin/bash thepid=0 stopnow=0 set -o monitor trap cleanup SIGINT SIGTERM cleanup() { trap - SIGINT SIGTERM stopnow=1 if [ ${thepid} -ne 0 ] then echo killing ${thepid} kill ${thepid} fi } while [ ${stopnow} -ne 1 ] do echo starting ./trial.sh & thepid=$! echo "waiting on ${thepid}" wait ${thepid} done exit 0