Linux Bash脚本捕获信号,但随后等待进程终止
目前我正在编写一个bash脚本,如下所示:Linux Bash脚本捕获信号,但随后等待进程终止,linux,bash,signals,Linux,Bash,Signals,目前我正在编写一个bash脚本,如下所示: foo(){ 虽然是真的 做 睡眠10 完成 } bar(){ 虽然是真的 做 睡20 完成 } 福& 酒吧& 等待 (我知道这样的剧本没有意义,只是结构而已) 现在我想用trap--RTMIN+1添加信号处理。一开始这是可行的。当脚本接收到rtmin+1信号时,它会做一些事情,但之后它就存在了(使用163退出代码,这是正在发送的信号的编号) 这不是我想要的行为。我希望在接收到信号后,脚本继续等待进程(在本例中是两个函数)终止(在本例中当然不会发生这
foo(){
虽然是真的
做
睡眠10
完成
}
bar(){
虽然是真的
做
睡20
完成
}
福&
酒吧&
等待
(我知道这样的剧本没有意义,只是结构而已)
现在我想用trap--RTMIN+1
添加信号处理。一开始这是可行的。当脚本接收到rtmin+1信号时,它会做一些事情,但之后它就存在了(使用163退出代码,这是正在发送的信号的编号)
这不是我想要的行为。我希望在接收到信号后,脚本继续等待进程(在本例中是两个函数)终止(在本例中当然不会发生这种情况,但脚本应该等待)
我尝试添加一个;等待
接收信号时应该做的事情,但这没有帮助(或者我做错了什么)
有人知道如何达到期望的行为吗
提前感谢并致以最良好的祝愿
编辑:也许一个更精确的例子有助于:
clock(){
本地前缀=C
局部间隔=1
虽然是真的
做
printf“${prefix} $(日期'+%d.%m%H:%m:%S')\n
睡眠时间间隔
完成
}
卷(){
前缀=V
volstat=“$(amixer get Master 2>/dev/null)”
echo“$volstat”| grep“\[off\]”>/dev/null&&icon=”" #备选方案:聋人: 静音:
vol=$(echo“$volstat”| grep-o“\[[0-9]\+%\]”sed“s/[^0-9]*///g;1q”)
如果[-z“$icon”];则
如果[“$vol”-gt“50”];则
图标=”"
#elif[“$vol”-gt“30”];然后
#图标=”"
其他的
图标=”"
fi
fi
printf“${prefix}%s%3s%%\n”“$icon”“$vol”
}
钟&
卷&
陷阱--“卷”RTMIN+2
等待
现在,RTMIN+2
信号应该重新运行volume
功能,但是时钟
过程不应该中断。(到目前为止,整个脚本(包括所有子过程)在接收到信号时终止)重写了一些内容
为了避免一些无用的叉子
clock(){ local prefix=C interval=2
trap : RTMIN{,+{{,1}{1,2,3,4,5},6,7,8,9,10}}
while :;do
printf "%s: %(%d.%m %H:%M:%S)T\n" $prefix -1
sleep $interval
done
}
volume(){ local prefix=V vol=() field playback val foo
while IFS=':[]' read field playback val foo;do
[ "$playback" ] && [ -z "${playback//*Playback*}" ] && [ "$val" ] &&
vol+=(${val%\%})
done < <(amixer get Master)
suffix='%%'
if [ "$vol" = "off" ] ;then
icon="" #alternative: deaf: mute:
suffix=''
elif (( vol > 50 )) ;then icon=""
elif (( vol > 30 )) ;then icon=""
else icon=""
fi
printf -v values "%3s$suffix " ${vol[@]}
printf "%s%s %s\n" $prefix "$icon" "$values"
}
clock & volume &
trap volume RTMIN+2
trap : RTMIN{,+{{,1}{1,3,4,5},6,7,8,9,10,12}}
echo -e "To get status, run:\n kill -RTMIN+2 $$"
while :;do wait ;done
有关
wait
命令如何工作和良好实践的更多信息,请查看good当在没有操作数的情况下调用时,wait
以0退出,这意味着调用shell已知的所有进程ID都已终止,或者值大于128,这意味着whi的信号接收到陷阱已设置。因此,循环直到wait
以0
退出足以在接收到信号后使脚本保持活动状态。您还可以检查其退出状态在循环中是否小于128,但我认为这没有必要
但是,如果您使用pkill
发送这些信号,则在后台启动的作业也将接收这些信号,因为子进程从其父进程继承进程名称,而不是从自定义信号处理程序继承,并且pkill
向名称匹配的所有进程发送信号。您也需要处理这种情况
一个最低限度的工作示例是:
#! /bin/bash -
# ignore RTMIN+1 and RTMIN+2 temporarily
# to prevent pkill from killing jobs
trap '' RTMIN+1 RTMIN+2
# start jobs
sleep 20 && echo slept for 20 seconds &
sleep 30 && echo slept for 30 seconds &
# set traps
trap 'echo received rtmin+1' RTMIN+1
trap 'echo received rtmin+2' RTMIN+2
# wait for jobs to terminate
until wait; do
echo still waiting
done
还值得注意的是,在开始作业之前忽略RTMIN+1
和RTMIN+2
会阻止外壳从它们下降而捕获/重置这些信号。如果这是一个问题,您可以按照F.Hauri的建议在作业中设置一个空陷阱;或者您可以完全放弃忽略,并将pkill
与-o
一起使用选择将信号发送到最早的匹配进程
参考资料:
替换等待
,while:;do wait;echo“V:$vol;done
这是你在回答中阐述的相同想法吗?是:等待
将在接收到某个信号时终止。因此你必须循环。echo“V:“$vol
可以帮助您查看执行时刻。您是否发送了RTMIN+2
或RTMIN+1
?我发送了RTMIN+2
您能否详细说明一下这一点为什么有效,而前一个无效?您必须向主pid发送信号,而不是向时钟子进程发送信号!您的环境(操作系统、版本)是什么?您可以通过将trap:
添加到clock
子流程中来避免退出子流程。查看我的上一次编辑。我删除了echo…| grep…| sed…,替换为纯bash循环。(Notased's/*\[\(off\\[0-9]\+\)%\?\]./\1/;ta;bb;:a;q;:b;d'有一些改进:尽可能使用整数测试,在立体声系统中打印左右音量,方法是将$values
输出准备为单独的步骤。错误:立体声系统中只测试左输出:左=右=100%将失败(百分比符号将丢失,图标将错误)。
volume(){
local prefix=V vol=() field playback val foo icons=(⏻ ¼ ¼ ¼ ½ ½ ¾ ¾ ¾ ¾ ¾)
local -i overallvol=0
while IFS=':[]' read field playback val foo ;do
[ "$playback" ] && [ -z "${playback//*Playback*}" ] && [ "$val" ] && {
vol+=($val)
val=${val%\%}
overallvol+=${val//off/0}
}
done < <(
amixer get Master
)
overallvol=$overallvol/${#vol[@]}
printf "%s%s %s\n" $prefix "${icons[(9+overall)/10]}" "${vol[*]}"
until wait;do :;done
#! /bin/bash -
# ignore RTMIN+1 and RTMIN+2 temporarily
# to prevent pkill from killing jobs
trap '' RTMIN+1 RTMIN+2
# start jobs
sleep 20 && echo slept for 20 seconds &
sleep 30 && echo slept for 30 seconds &
# set traps
trap 'echo received rtmin+1' RTMIN+1
trap 'echo received rtmin+2' RTMIN+2
# wait for jobs to terminate
until wait; do
echo still waiting
done