睡眠、等待和 Ctrl+C 传播

Har*_*jan 8 bash sleep wait

如果我有以下 shell 脚本

sleep 30s
Run Code Online (Sandbox Code Playgroud)

Ctrl+C在 shell 脚本运行时命中sleep,它随之消失。

如果我有以下 shell 脚本

sleep 30s &
wait
Run Code Online (Sandbox Code Playgroud)

Ctrl+C在 shell 脚本运行时命中,sleep继续,现在父级为 1。

这是为什么?bash 不会传播Ctrl+C给所有孩子吗?

编辑:如果我有以下脚本

/usr/bin/Xvfb :18.0 -ac -screen 0 1180x980x24 &
wait
Run Code Online (Sandbox Code Playgroud)

我在那里生成一个程序,这次Ctrl+C在主Xvfb进程上也会杀死该进程。

那么如何/为什么Xvfb与睡眠不同?

在某些进程的情况下,我看到它们被 收割init,在某些情况下它们会死亡。为什么睡眠会被 init 收获?为什么会Xvfb死?

mos*_*svy 10

tl;博士; Xvfb过程设置了一个信号处理器SIGINT和退出时,它接收到这样的信号,但是sleep过程中没有,所以它继承了“忽略”状态SIGINT,因为它是通过执行之前运行脚本的外壳设置sleep二进制。

当 shell 脚本运行时,作业控制被关闭,后台进程(以 开头的那些&)只是在同一个进程组中运行,SIGINTSIGQUIT设置为SIG_IGN(忽略)并且它们的标准输入从 重定向/dev/null

这是标准要求的:

如果在 shell 执行异步列表时禁用作业控制(参见 set -m 的描述),则列表中的命令应从 shell 继承一个忽略(SIG_IGN)的信号操作,用于 SIGINT 和 SIGQUIT 信号。

如果信号处置设置为SIG_IGN(忽略),则该状态将通过fork()和继承execve()

在调用进程映像中设置为默认操作(SIG_DFL)的信号应设置为新进程映像中的默认操作。除了 SIGCHLD,调用进程映像设置为忽略的信号 (SIG_IGN) 应设置为新进程映像忽略。

  • 在最新版本的 `bash` 中,可以通过将命令作为 `coproc` 而不是 `&` 来启动命令来解决这个问题: `{ coproc sleep 30 < /dev/null >&4 4>&-; 4>&1` 似乎没有忽略 SIGINT/SIGQUIT... (3认同)
  • POSIX 还禁止 shell 允许撤销 SIG_IGN。`zsh` 忽略了这个(无用的)要求,所以在 `zsh` 中,你可以使用 `(trap - INT; sleep 30) &` 来解决它。在其他 shell 中,您需要使用 `zsh -c 'trap - INT; exec sleep 30' &` 或使用 `perl` 或其他没有那个愚蠢要求的东西。 (2认同)

Jef*_*ler 5

bash 手册页

\n\n
\n

后台进程是进程组ID与终端\xe2\x80\x99s不同的进程;此类进程不受键盘生成信号的影响

\n
\n\n

你可以用不同的方式来处理这个问题;首先,杀死列出的作业:

\n\n
#!/bin/bash\ntrap \'kill $(jobs -p)\' INT\nsleep 30s &\nwait\n
Run Code Online (Sandbox Code Playgroud)\n\n

或者,向同一进程组中的所有进程发送终止命令:

\n\n
#!/bin/bash\ntrap \'kill 0\' INT\nsleep 30s &\nwait\n
Run Code Online (Sandbox Code Playgroud)\n