Bash脚本没有看到SIGHUP?


11

我有以下脚本:

#!/bin/bash
echo "We are $$"
trap "echo HUP" SIGHUP
cat    # wait indefinitely

当我发送SIGHUP(使用kill -HUP pid)时,没有任何反应。

如果我稍微更改脚本:

#!/bin/bash
echo "We are $$"
trap "kill -- -$BASHPID" EXIT    # add this
trap "echo HUP" SIGHUP
cat    # wait indefinitely

...然后脚本在echo HUP退出时会正确执行操作(当我按Ctrl + C时):

roger@roger-pc:~ $ ./hupper.sh 
We are 6233
^CHUP

这是怎么回事?我应该如何SIGHUP向该脚本发送信号(不一定是)?


4
cat过程完成后,将传递信号并执行信号处理程序。尝试使用原始脚本,然后按退出Ctrl+Dcat过程。当cat过程处于前台时,HUP不会作用信号。再用cat替换为read(内置shell)再试一次。
库萨兰达

完善。有人愿意把它变成答案吗?
罗杰·利普斯科姆

我知道它可以这样工作,但是我会让一个比我更有洞察力的人来研究为什么以及为什么要这样做的答案。
Kusalananda

我最后使用while true; do read; done过,否则输入文本也会使其退出,并且我希望它在Ctrl + C时退出。
罗杰·利普斯科姆

Answers:


21

Bash手册指出:

如果bash正在等待命令完成并接收到已设置陷阱的信号,则在命令完成之前将不执行陷阱。

这意味着,尽管bash在您发送信号时已收到信号,但仅在cat结束时才会调用SIGHUP上的陷阱。

如果这种行为是不受欢迎的,则可以使用bash内置函数(例如,用read+ printf代替循环cat)或使用后台作业(请参阅Stéphane的答案)。


9

@xhienne已经解释了为什么,但是如果您想立即使信号起作用(并且不退出脚本),则可以将代码更改为:

#! /bin/bash -
interrupted=true
trap 'interrupted=true; echo HUP' HUP

{ cat <&3 3<&- & pid=$!; } 3<&0

while
  wait "$pid"
  ret=$?
  "$interrupted"
do
  interrupted=false
done
exit "$ret"

使用文件描述符的小动作是为了解决以下事实:bash将stdin重定向到/dev/null后台启动的命令。


因为代码块在子shell中运行,这行得通吗?
Pysis
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.