我有一个脚本在后台启动另一个脚本,然后终止它。我期待儿童脚本消失,但最终仍然设法打印一些输出。这是一个例子:
脚本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但不在后台运行!输出是get:
this is one
this is two
this is three
this was one
this was three
由于three.sh没有在后台运行而且two.sh被one.sh终止,所以不应该在输出中出现“this is three”您是否也可以向我指出任何文档,这些文档描述了在后台(不)在后台处理过程时的行为以及终止时会发生什么?
非常感谢你的帮助!
答案 0 :(得分:2)
当你从bash脚本启动一个新进程时,这基本上是通过fork()完成的。
新进程(称为子进程)与调用进程完全相同,称为父进程(除了可以在man fork中找到的多个点之外)。
如果父母去世,孩子就会成为初始过程的孩子。 然后,init进程的作用是在它退出后收集子进程的返回代码(reaping)。因此,当你杀死“两个”时,“三个”并没有被杀死但只是得到一个不同的父母。这就是落后三人的原因。
这个问题是从C点的角度讨论的:How to make child process die after parent exits?
答案 1 :(得分:1)
答案 2 :(得分:0)
这看起来令人惊讶的原因是人们可能期望TERM信号(默认来自“kill”)传播到子进程,换句话说,SIGTERM信号(信号#15)由two.sh接收也将传播到three.sh。但实际情况并非如此。杀死two.sh只需将three.sh留给“init”进程(进程ID 1)作为其新的父进程,init将在three.sh退出后进行清理。
进程组的情况变得更加复杂,bash文档讨论了如何将键盘生成的信号发送到前台进程组中的所有进程,通常是在没有“&”的情况下运行的管道。最后。但是,这些问题不适用于示例脚本。
注意:在Unix中,不应在可执行脚本上使用“.sh”扩展名。专注于在第一行放置正确的“#!/ bin / bash”或“#!/ bin / sh”。命令不应该在命令名中公开它们的实现语言,以免后来在实现语言改变时必须留下错误的语言,但是其他代码已经依赖于原来的,现在不正确的扩展。