如何使用信号从自身重新启动BASH脚本?

3
例如,我有一个带有无限循环打印东西到标准输出的脚本。我需要捕获一个信号(例如SIGHUP),这样它将使用不同的PID重新启动脚本,并使循环从0开始再次运行。杀掉和重新启动没有预期的效果:
function traphup(){  
    kill $0  
    exec $0
}  
trap traphup HUP

也许我应该将一些东西放在后台或使用nohup命令,但我不熟悉这个命令。
1个回答

4

在你的函数中:

traphup(){
    $0 "$@" &
    exit 0
}

这将使用原始命令名称和参数(根据您的要求变化参数)在后台启动一个新进程,具有新的进程ID。原始shell然后退出。如果您的守护程序使用PID文件来标识自己,请不要忘记解决PID文件问题-但是重新启动可能会自动完成这个过程。
请注意,使用nohup是错误的方向;第一次启动守护程序时,它将响应HUP信号,但使用nohup启动的守护程序将忽略该信号,不会再次重启-除非您明确覆盖了“忽略”状态,这是因为各种原因都不好的想法。
回答评论:
我不太确定问题出在哪里。
当我运行以下脚本时,无论我是将其作为./xx.sh启动还是作为./xx.sh&启动,我在ps输出中只看到一个脚本副本。
#!/bin/bash

traphup()
{
    $0 "$$" &
    exit 0
}

trap traphup HUP
echo
sleep 1

i=1
while [ $i -lt 1000 ]
do
    echo "${1:-<none>}: $$: $i"
    sleep 1
    : $(( i++ ))
done

输出包含以下内容:

该输出包含这样的行:

<none>: 1155: 21
<none>: 1155: 22
<none>: 1155: 23

1155: 1649: 1
1155: 1649: 2
1155: 1649: 3
1155: 1649: 4

具有 '<none>' 的是原始进程;第二个集合是子进程(1649)报告其父进程(1155)。此输出使跟踪要发送HUP信号的进程变得容易。(初始echo和sleep将命令行提示从输出中移除。) 我怀疑你所看到的内容取决于你的脚本内容 - 在我的情况下,循环体很简单。但如果我在其中加入了管道或其他东西,那么可能会看到一个具有相同名称的第二个进程。但我不认为这会因原始脚本是在前台运行还是在后台运行而改变。

谢谢。只有一件事不是很清楚。如果我在前台运行我的脚本,并使用我的脚本名称grep ps结果,我将得到两个具有不同PID的项目。但是,如果我在后台运行脚本,我将只得到一个带有新PID的记录。这就是我需要的,但为什么这些执行类型之间会有差异呢? - Oink
我通常使用一个“for i in $(range 1 1000)”的程序,这对我很有效,但是对于那些没有这个程序的人来说就无法帮助他们。我已经不熟练在Bash中做这样的事情了——我必须在不是标准shell的机器上工作,过多地适应Bash最终对我不利。 - Jonathan Leffler
抱歉问个弱智问题,但为什么我应该在traphup()中以后台方式执行脚本?用常规的exec $0有什么问题吗? - Oink
@camh:我的意思是将“$0 "$$" &”更改为“$0 "$$"”。 - Oink
很可能我无法清楚地解释我不明白的事情。我们必须在重启信号后在后台运行脚本,否则它将永远不会得到“exit 0”,这就是为什么我同时在ps输出中运行了当前脚本和信号后启动的脚本。现在清楚了。 - Oink
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接