bash 使用陷阱 SIGCHLD 重新启动子进程?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6769414/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 00:24:48  来源:igfitidea点击:

bash restart sub-process using trap SIGCHLD?

bashchild-processbash-trapsigchld

提问by X.M.

I've seen monitoring programs either in scripts that check process status using 'ps' or 'service status(on Linux)' periodically, or in C/C++ that forks and wait on the process...

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

I wonder if it is possible to use bash with trap and restart the sub-process when SIGCLD received?

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

I have tested a basic suite on RedHat Linux with following idea (and certainly it didn't work...)

我已经使用以下想法在 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

what the bash script being started just sleep for a few seconds and exit for now.

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

several issues observed:

观察到的几个问题:

  • when the shell starts in foreground, SIGCHLD will be handled only once. does trap reset signal handling like signal()?
  • the script and its child seem to be immune to SIGINT, which means they cannot be stopped by ^C
  • since cannot be closed, I closed the terminal. The script seems to be HUP and many zombie children left.
  • when run in background, the script caused terminal to die
  • 当 shell 在前台启动时, SIGCHLD 将只处理一次。陷阱重置信号处理像信号()?
  • 脚本及其子进程似乎对 SIGINT 免疫,这意味着它们不能被 ^C 阻止
  • 由于无法关闭,我关闭了终端。剧本好像是HUP,很多丧尸小孩都走了。
  • 在后台运行时,脚本导致终端死机

... anyway, this does not work at all. I have to say I know too little about this topic. Can someone suggest or give some working examples? Are there scripts for such use?

……无论如何,这根本行不通。我不得不说我对这个话题知之甚少。有人可以建议或提供一些工作示例吗?是否有用于此类用途的脚本?

how about use wait in bash, then?

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

Thanks

谢谢

回答by jw013

I can try to answer some of your questions but not all based on what I know.

我可以尝试回答您的一些问题,但不能根据我所知道的全部回答。

  1. The line set -o monitor(or equivalently, set -m) turns on job control, which is only on by default for interactive shells. This seems to be required for SIGCHLD to be sent. However, job control is more of an interactive feature and not really meant to be used in shell scripts (see also this question).

    Also keep in mind this is probably not what you intended to do because once you enable job control, SIGCHLD will be sent for everyexternal command that exists (e.g. every time you run lsor grepor anything, a SIGCHLD will fire when that command completes and your trap will run).

  2. I suspect the reason the SIGCHLD trap only appears to run once is because your trap handler contains a foreground infinite loop, so your script gets stuck in the trap handler. There doesn't seem to be a point to that loop anyways, so you could simply remove it.

  3. The script's "immunity" to SIGINT seems to be an effect of enabling job control (the monitor part). My hunch is with job control turned on, the sub-instance of bash that runs your script no longer terminates itself in response to a SIGINT but instead passes the SIGINT through to its foreground child process. In your script, the ^Ci.e. SIGINT simply acts like a continuestatement in other programming languages case, since SIGINT will just kill the currently running sleep 60, whereupon the while loop will immediately run a new sleep 60.

  4. When I tried running your script and then killing it (from another terminal), all I ended up with were two stray sleep processes.

  5. Backgrounding that script also kills my shell for me, although the behavior is not terribly consistent (sometimes it happens immediately, other times not at all). It seems typing any keys other than enter causes an EOF to get sent somehow. Even after the terminal exits the script continues to run in the background. I have no idea what is going on here.

  1. 该行set -o monitor(或等效地,set -m)打开作业控制,默认情况下仅对交互式 shell 启用。这似乎是发送 SIGCHLD 所必需的。但是,作业控制更多的是一种交互式功能,并不真正打算在 shell 脚本中使用(另请参阅此问题)。

    还要记住,这可能不是您打算做的,因为一旦您启用作业控制,就会为每个存在的外部命令发送 SIGCHLD (例如,每次运行ls或执行grep任何操作时,当该命令完成并且您的陷阱将运行)。

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

  3. 脚本对 SIGINT 的“免疫”似乎是启用作业控制(监视器部分)的效果。我的预感是打开作业控制,运行脚本的 bash 子实例不再响应 SIGINT 而自行终止,而是将 SIGINT 传递到其前台子进程。在您的脚本中,^Cie SIGINT 的作用就像continue其他编程语言中的语句一样,因为 SIGINT 只会终止当前运行的sleep 60,然后 while 循环将立即运行新的sleep 60.

  4. 当我尝试运行您的脚本然后(从另一个终端)终止它时,我最终得到的只是两个流浪睡眠进程。

  5. 背景化该脚本也会为我杀死我的外壳,尽管行为不是非常一致(有时它会立即发生,有时根本不会发生)。似乎输入除 enter 之外的任何键都会导致 EOF 以某种方式发送。即使在终端退出后,脚本也会继续在后台运行。我不知道这里发生了什么。

Being more specific about what you want to accomplish would help. If you just want a command to run continuously for the lifetime of your script, you could run an infinite loop in the background, like

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

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

Note the &after the done.

注意&之后的done

For other tasks, waitis probably a better idea than using job control in a shell script. Again, it would depend on what exactly you are trying to do.

对于其他任务,wait可能比在 shell 脚本中使用作业控制更好。同样,这将取决于您究竟要做什么。