Bash 脚本没有看到 SIGHUP?

Bash 脚本没有看到 SIGHUP?

我有以下脚本:

#!/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向该脚本发送信号(不一定是)?

答案1

Bash 手册状态:

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

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

如果这种行为是不可取的,则可以使用bash内置函数(例如,循环中的read+而不是)或使用后台作业(请参阅printfcat史蒂芬的回答)。

答案2

@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后台启动的命令这一事实。

答案3

我注意到,当 EXIT 上有陷阱时,脚本在收到信号时不会等待外部命令结束。示例脚本:

$ cat test-trap 
#!/bin/bash
echo "We are $$"
trap "echo 'Trapping EXIT'" EXIT
cat

运行它:

$ ./test-trap
We are 24814

向其发送 SIGHUP:

$ ./test-trap
We are 24814
# Doing `kill -HUP 24814` in another terminal
Trapping EXIT
Hangup

不过,可能有一只困惑的被遗弃的猫:

cat: -: Input/output error

为了解决这个问题,您可能需要从陷阱调用的函数中搜索并终止子进程。

Ctrl+ C

$ ./test-trap
We are 24814
^CTrapping EXIT

现在,当您按Ctrl+D而不是Ctrl+时C,cat 命令会正常结束。但是当脚本结束时陷阱就会被执行:

$ ./test-trap
We are 40183
# I pressed Ctrl+D here...
Trapping EXIT

您可以通过取消脚本末尾的陷阱来防止这种情况:

#!/bin/bash
echo "We are $$"
trap "echo 'Trapping EXIT'" EXIT
cat
trap - EXIT

我无法找到有关捕获 EXIT 的这种不同行为的任何文档。也许其他人可以?

相关内容