【问题标题】:How do making processes with & (in bash) and killing them work?使用 & (在 bash 中)创建进程并杀死它们如何工作?
【发布时间】:2013-06-28 15:15:45
【问题描述】:

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

在脚本 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 终止,因此输出中不应该出现“this was three”吗?您能否向我指出任何描述进程在(非)后台时的行为以及终止时会发生什么的文档?

非常感谢您的帮助!

【问题讨论】:

    标签: bash process


    【解决方案1】:

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

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

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

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

    【讨论】:

    • init进程不会杀死孩子;它只是收集尸体(僵尸)的统计数据,这样僵尸就不会无限制地积累。
    【解决方案2】:

    您正在杀死后台进程 two.sh,但不是 two.sh 及其子进程 three.sh

    这个问题:

    Best way to kill all child processes

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

    【讨论】:

      【解决方案3】:

      这看起来令人惊讶的原因是,人们可能期望 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”放在第一行。命令不应在命令名称中公开其实现语言,以免以后在实现语言更改时不得不留下错误的语言,但其他代码已经开始依赖原始的,现在不正确的扩展。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-10-23
        • 2021-02-23
        相关资源
        最近更新 更多