目前我正在编写这样的bash脚本:
foo(){
while true
do
sleep 10
done
}
bar(){
while true
do
sleep 20
done
}
foo &
bar &
wait
(我知道这样的脚本没有意义,它只是关于结构(
现在我想添加trap -- <doSomething> RTMIN+1
的信号处理。这在一开始是有效的。当脚本接收到rtmin+1信号时,它确实做了一些事情,但之后它就存在了(退出代码为163,这是正在发送的信号的编号(。
这不是我想要的行为。我希望在收到信号后,脚本继续等待进程(在本例中是两个函数(终止(当然,在本例中将不会发生这种情况,但脚本应该等待(。
我尝试在接收信号时将; wait
添加到应该做的事情中,但这没有帮助(或者我做错了什么(。
有人知道如何实现期望的行为吗?
提前感谢并致以最良好的祝愿。
编辑:也许一个更精确的例子有帮助:
clock(){
local prefix=C
local interval=1
while true
do
printf "${prefix} $(date '+%d.%m %H:%M:%S')n"
sleep $interval
done
}
volume(){
prefix=V
volstat="$(amixer get Master 2>/dev/null)"
echo "$volstat" | grep "[off]" >/dev/null && icon="" #alternative: deaf: mute:
vol=$(echo "$volstat" | grep -o "[[0-9]+%]" | sed "s/[^0-9]*//g;1q")
if [ -z "$icon" ] ; then
if [ "$vol" -gt "50" ]; then
icon=""
#elif [ "$vol" -gt "30" ]; then
# icon=""
else
icon=""
fi
fi
printf "${prefix}%s %3s%%n" "$icon" "$vol"
}
clock &
volume &
trap -- "volume" RTMIN+2
wait
现在RTMIN+2
信号应该重新运行volume
函数,但clock
过程不应该中断。(到目前为止,整个脚本(包括所有子流程(在接收到信号时终止(
当在没有操作数的情况下调用时,wait
会以0退出;这意味着调用shell已知的所有进程ID都已终止,或者值大于128;这意味着已经设置了陷阱的信号被接收。因此,循环直到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
选项将信号发送到最旧的匹配进程。
参考文献:
- 外壳命令语言§信号和错误处理
wait
规范§退出状态
相关:
- USR1信号后可靠终止睡眠过程
某些已重写
为了避免一些无用的叉子。
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)Tn" $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 %sn" $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
关于我上次关于立体声错误的评论,有一个音量函数适用于立体声、单声道甚至四声道:
volume(){
local prefix=V vol=() field playback val foo
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[@]}
if (( overallvol == 0 )) ;then
icon=""
elif (( overallvol > 50 )) ;then
icon=""
elif (( overallvol > 30 )) ;then
icon=""
else
icon=""
fi
printf "%s%s %sn" $prefix "$icon" "${vol[*]}"
}
甚至:
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 %sn" $prefix "${icons[(9+overall)/10]}" "${vol[*]}"
一些解释
关于volume()
函数中的无用叉子
我在那里发布了一些改进工作的想法,减少资源消耗,并做同样的工作,选择图标作为当前音量集的函数。
关于while :;do wait;done
循环
由于所请求的示例代表了在后台子函数中的无限循环,所以主脚本使用相同的无限循环。
但由于问题标题代表等待进程终止,我不得不同意oguz-ismail的评论。
事实上,最后一行最好写:
until wait;do :;done
有关wait
命令如何工作和良好实践的更多信息,请查看good-oguz-ismail的答案