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
只打印一次,但repeat
fork 永远存在,无休止地打印。
我应该如何防止repeat
在创建它的脚本退出后继续运行?
我认为可能明确实例化一个新的bash -c
解释器会迫使它在其父级消失时退出,但我猜孤立进程被init
PID 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)
但是你最好不要有另一个重要的过程以这个名字命名,否则它也会被抹杀。
我想知道,是否有更好或可接受的方法来处理在创建它们的脚本(或进程)退出时应该退出的分叉 shell 中的后台作业?
如果没有比盲目地pkilling
使用相同名称的所有进程更好的方法,那么应该如何处理与网络服务器之类的东西一起运行的重复作业以退出?我想避免cron
工作,因为脚本位于git
存储库中,并且代码应该是自包含的,而无需更改/etc/
.
这会在脚本退出之前终止后台进程:
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)