理解bash信号处理 前言

理解bash信号处理 前言,bash,exception,audio,signals,bash-trap,Bash,Exception,Audio,Signals,Bash Trap,我最初的意图是编写一个脚本,每1秒检查一次什么硬件可能更好?正在播放Spotify音乐耳机、立体声,。。。这样,即使Spotify在中终止后,该信息仍然可靠,这是Spotify关闭时使用的硬件id 我最初为此编写的脚本本质上是一个在while true循环中调用和解析pactl list的脚本,以检索Spotify播放音频的硬件的id 只要Spotify启动,它就可以工作,但当Spotify关闭时,该侦听器的最终结果是一个空字符串,如果在关闭Spotify后调用pactl info,这对我来说似

我最初的意图是编写一个脚本,每1秒检查一次什么硬件可能更好?正在播放Spotify音乐耳机、立体声,。。。这样,即使Spotify在中终止后,该信息仍然可靠,这是Spotify关闭时使用的硬件id

我最初为此编写的脚本本质上是一个在while true循环中调用和解析pactl list的脚本,以检索Spotify播放音频的硬件的id

只要Spotify启动,它就可以工作,但当Spotify关闭时,该侦听器的最终结果是一个空字符串,如果在关闭Spotify后调用pactl info,这对我来说似乎没什么问题,但我认为我以前调用过它

在这一点上,我想我可能误解了信号处理和陷阱在bash中是如何工作的

纳努威酒店 为了给我自己和你一个MWE,我提出了以下建议

driver.sh脚本在后台启动listener.sh脚本,然后在后台启动Spotify而不是我的理解是,这样做,向Spotify发送信号,例如关闭信号,会导致信号发送到driver.sh;它还设置陷阱,终止后台进程。 一个listener.sh脚本,在while-true循环中无限地解析行media.name的pactl列表输出;陷阱确保解析在终止时最后发生一次。 我认为,给定此设置,从终端执行driver.sh将导致以下结果

Spotify打开,然后用表单中的行一秒一秒地填充终端 通过关闭driver.sh或关闭Spotify窗口关闭Spotify后,再行两行: 相反,如果我关闭Spotify,我得到的是

...
func: media.name = "Spotify"
func: media.name = "Spotify"
+enrico:~$ trap:
func: # empty!
trap:
func: # why again?
如果我改为CTRL+C driver.sh,我得到的评论是我的:

...
func: media.name = "Spotify"
func: media.name = "Spotify"
^Cfunc: media.name = "Spotify"   # here I hit ctrl+c
func: media.name = "Spotify"     # maybe this delay is because of sleep in listener.sh?
./spot.sh: line 6:  8704 Segmentation fault      (core dumped) /usr/bin/spotify # why this SegV?
+enrico:~$ trap:
func: # empty!
trap:
func: # why again?
这让我很困惑。我认为在接收到终止信号后,driver.sh应该用陷阱捕获它,并运行kill-TERM$bg_pid命令来处理它。反过来,listener.sh在接收到信号后,应该执行echo,然后执行func,然后退出。只有在这一点上,Spotify才会终止。如果在这之后调用pactl列表中没有Spotify,我会理解的

显然,我可能误解了整件事。

/usr/bin/spotify接收到SIGINT并在driver.sh终止listen.sh之前死亡,因此pactl的空输出。您应该在后台运行/usr/bin/spotify,并在终止listen.sh后终止它

因此,您的脚本应该如下所示:

driver.sh

听着,嘘


Spotify在您点击Ctrl-C时接收到SIGINT,然后driver.sh将其捕获并杀死listener.sh。是什么让你认为只有在这一点上Spotify才应该终止?我想我对这个主题缺乏知识。然而,这可以解释为什么当我关闭Spotify从而向它发送信号时,行为是这样的。但是如果我在driver.sh运行的终端中按ctrl-c。。。它如何在处理代码异常之前终止?了解bash如何运行命令可能会有所帮助。当/usr/bin/spotify行运行时,1个bash分叉,2个子进程执行spotify,3个bash阻塞信号并开始等待子进程死亡。当你点击Ctrl-C时,1它杀死了孩子,2 bash看到了这一点并解除了信号阻塞,3 bash收到INT,采取行动。好的。顺便说一句,阻止spotify进行segfaulting在这里是不可能的,这是由其设计中的一个错误引起的。在理解了这个主题后,多亏了这个评论和答案,我意识到我最初的意图确实是@usr确定的:在spotify中插入一个信号处理程序。现在我明白了为什么这是不可能的。谢谢你们两位,我将接受这个答案,因为它确实说明了我所能做的最好的事情:在spotify的包装中插入一个信号处理程序。为了让它正常工作,我必须通过包装器关闭spotify,就像我直接关闭spotify一样,包装器将在为时已晚时采取行动。感谢您的回答和评论,这两方面都帮助我理解。唯一遗憾的是,你删除了一条带有很好链接的评论,其他人本可以从中受益。我自己,将不得不在我的浏览器历史中挖掘这个链接。@Enrico,与这个问题无关,虽然可能无关,但可能对感兴趣的读者有用。我的意思是,我的问题试图指出信号处理的一个具体用例,也许它没有,基于-1和投票结束它,但读者可能会对信号处理有更广泛的兴趣。@Enrico好的,那么我就把它放在这里。在投票结束后,如果没有spotify和pactl,这个问题可能会变得更简短、更清晰;而且会得到更好的答案。也许这就是我事后同意的原因。
func: media.name = "Spotify"
func: media.name = "Spotify"
func: media.name = "Spotify"
...
trap:
func: media.name = "Spotify"
...
func: media.name = "Spotify"
func: media.name = "Spotify"
+enrico:~$ trap:
func: # empty!
trap:
func: # why again?
...
func: media.name = "Spotify"
func: media.name = "Spotify"
^Cfunc: media.name = "Spotify"   # here I hit ctrl+c
func: media.name = "Spotify"     # maybe this delay is because of sleep in listener.sh?
./spot.sh: line 6:  8704 Segmentation fault      (core dumped) /usr/bin/spotify # why this SegV?
+enrico:~$ trap:
func: # empty!
trap:
func: # why again?
#!/bin/bash
trap 'kill -TERM $bg_pid $!' SIGINT SIGTERM
./listen.sh &
bg_pid=$!
echo "bg_pid: $bg_pid"
/usr/bin/spotify &
wait
#!/bin/bash
trap 'echo trap:; func; exit' SIGINT SIGTERM
func() {
  echo func: $(pactl list | sed -E '/media\.name/p;d')
}
while true; do
  func
  sleep 1
done