9

我有一个脚本在后台启动另一个脚本,然后终止它。我原以为子脚本会消失,但最后它仍然设法打印一些输出。这是示例:

在脚本 one.sh 中:

echo "this is one"
./two.sh &
sleep 1
pid=$!
kill $pid
echo "this was one"

在脚本 two.sh 中:

echo "this is two"
./three.sh
echo "this was two"

在脚本 three.sh 中:

echo "this is three"
sleep 5
echo "this was three"

我运行了 ./one.sh,它应该在后台运行 two.sh,而后者又运行 three.sh 但不在后台!得到的输出是:

this is one
this is two
this is three
this was one
this was three

由于three.sh没有在后台运行并且two.sh被one.sh终止,所以“这是三”不应该出现在输出中吗?您能否向我指出任何描述进程在(非)后台时的行为以及它们终止时会发生什么的文档?

非常感谢您的帮助!

4

3 回答 3

2

当您从 bash 脚本启动新进程时,这基本上是通过 fork() 完成的。

新进程,称为子进程,是调用进程(称为父进程)的完全复制品(除了一些可以在 man fork 中找到的点)。

如果父进程死亡,则子进程将成为 init 进程的子进程。然后它是 init 进程的角色,收集孩子退出后的返回码(收割)。因此,当您杀死“二”时,“三”不会被杀死,而只是获得了不同的父级。这就是尾随三个的原因。

这里从 C 的角度讨论这个问题:How to make child process die after parent exits?

于 2013-06-28T15:44:01.283 回答
1

您正在杀死后台进程two.sh,但没有杀死two.sh它的子进程three.sh

这个问题:

杀死所有子进程的最佳方法

有更多关于杀死子进程的信息。

于 2013-06-28T15:36:31.337 回答
0

这可能看起来令人惊讶的原因是人们可能期望 TERM 信号(“kill”的默认值)被传播到子进程,换句话说,两个.sh 接收到的 SIGTERM 信号(信号#15)将被传播到三个.sh 为好。然而,事实并非如此。杀死 two.sh 只是将 three.sh 留给“init”进程(进程 ID 1)作为其新的父进程,并且 init 将在三个.sh 退出后进行清理。

进程组的情况变得更加复杂,bash 文档讨论了如何将键盘生成的信号发送到前台进程组中的所有进程,通常是在没有“&”结尾的情况下运行的管道。但是,这些问题不适用于示例脚本。

注意:在 Unix 中,您不应该在可执行脚本上使用“.sh”扩展名。专注于将正确的“#!/bin/bash”或“#!/bin/sh”放在第一行。命令不应在命令名称中公开其实现语言,以免以后在实现语言更改时不得不留下错误的语言,但其他代码已经开始依赖原始的,现在不正确的扩展。

于 2013-06-28T21:47:12.237 回答