首页 > 解决方案 > Bash 脚本捕获信号,但之后等待进程终止

问题描述

目前我正在编写这样的 bash 脚本:

foo(){
  while true
  do
    sleep 10
  done
}

bar(){
  while true
  do
    sleep 20
  done
}

foo &
bar &

wait

(我知道这样的脚本没有意义,它只是关于结构)

现在我想用trap -- <doSomething> RTMIN+1. 这首先有效。当脚本接收到 rtmin+1 信号时,它会做 doSomething 但之后它存在(带有 163 退出代码,这是正在发送的信号的编号)。

这不是我想要的行为。我希望在收到信号后,脚本继续等待进程(在这种情况下是两个函数)终止(在这种情况下当然不会发生,但脚本应该等待)。

我尝试将 a 添加; 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过程不应该被中断。(到目前为止,整个脚本(包括所有子进程)在收到信号后终止)

标签: linuxbashsignals

解决方案


当没有操作数调用时,以0wait退出;这意味着调用 shell 已知的所有进程 ID 都已终止,或者值大于 128;这意味着接收到已设置陷阱的信号。因此,循环直到退出就足以让脚本在收到信号后保持活动状态。您也可以在循环中检查其退出状态是否小于 128,但我认为没有必要。wait0

但是,如果您使用 发送这些信号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+1RTMIN+2在开始作业之前忽略它们可以防止从它们下降的 shell 捕获/重置这些信号。如果这是一个问题,您可以按照 F. Hauri 的建议在工作中设置一个空陷阱;或者您可以完全放弃忽略并使用pkill选项-o将信号发送到最旧的匹配进程。

参考:

有关的:


推荐阅读