防止 shell 分叉比它的发起者活得更久?

cat*_*cat 4 bash fork concurrency jobs background-process

如果我有一个 Bash 脚本,例如:

function repeat {
    while :; do
        echo repeating; sleep 1
    done
}
repeat &
echo running once
Run Code Online (Sandbox Code Playgroud)

running once只打印一次,但repeatfork 永远存在,无休止地打印。

我应该如何防止repeat在创建它的脚本退出后继续运行?

我认为可能明确实例化一个新的bash -c解释器会迫使它在其父级消失时退出,但我猜孤立进程被initPID 1 采用。

使用另一个文件对此进行测试:

# repeat.bash
while :; do echo repeating; sleep 1; done

# fork.bash
bash -c "./repeat.bash & echo an exiting command"
Run Code Online (Sandbox Code Playgroud)

运行./fork.bash仍然会导致repeat.bash永远在后台继续运行。

简单而懒惰的解决方案是将行添加到fork.bash

pkill repeat.bash
Run Code Online (Sandbox Code Playgroud)

但是你最好不要有另一个重要的过程以这个名字命名,否则它也会被抹杀。

  1. 我想知道,是否有更好或可接受的方法来处理在创建它们的脚本(或进程)退出时应该退出的分叉 shell 中的后台作业?

  2. 如果没有比盲目地pkilling使用相同名称的所有进程更好的方法,那么应该如何处理与网络服务器之类的东西一起运行的重复作业以退出?我想避免cron工作,因为脚本位于git存储库中,并且代码应该是自包含的,而无需更改/etc/.

Joh*_*024 5

这会在脚本退出之前终止后台进程:

trap '[ "$pid" ] && kill "$pid"' EXIT

function repeat {
    while :; do
        echo repeating; sleep 1
    done
}
repeat &
pid=$!
echo running once
Run Code Online (Sandbox Code Playgroud)

这个怎么运作

  • trap '[ "$pid" ] && kill "$pid"' EXIT

    这会造成一个陷阱。每当脚本即将退出时,将运行单引号中的命令。该命令检查是否为 shell 变量pid分配了一个非空值。如果是,则与其关联的进程pid被终止。

  • pid=$!

    这会将前面的后台命令 ( repeat &)的进程 ID 保存在 shell 变量中pid

改进

正如帕特里克在评论中指出的,有机会的话,该脚本可以被杀死之后,后台进程启动,但之前pid变量。我们可以使用以下代码处理这种情况:

my_exit() {
    [ "$racing" ] && pid=$!
    [ "$pid" ] && kill "$pid"
}
trap my_exit EXIT

function repeat {
    while :; do
        echo repeating; sleep 1
    done
}

racing=Y
repeat &
pid=$!
racing=

echo running once
Run Code Online (Sandbox Code Playgroud)