我有一个控制一些附属脚本的主脚本。当我从终端发送中断信号时,父级trap
捕获了该信号,但子级没有捕获信号,我不明白为什么。我没有更改默认终端设置(我没有stty
在任何地方运行)。
这是我的父脚本和子脚本以及终端输出:
家长:
#!/bin/sh
./child.sh &
for sig in $(kill -l) ; do
trap "echo parent:$sig" $sig
done
wait
孩子:
#!/bin/sh
cat < /dev/tty &
PID=$!
for sig in $(kill -l) ; do
trap "echo child:$sig" $sig
done
wait
终端交互:
[prompt]$ ./parent.sh
^Cparent:INT
cat: stdin: Input/output error
[prompt]$
更新
我在 macOS 和 CentOS 上测试了该脚本,出现了上述行为。当我使用默认的 Bourne 兼容 shell 在 FreeBSD 上测试它时,子进程收到的信号是CHLD
。
答案1
对于由非交互式 shell 异步运行的命令(实际上当未启用作业控制时),SIGINT 和 SIGQUIT 在 POSIX 兼容中被忽略sh
POSIX 要求尽管有些 shell 会忽略它。
另一个 POSIX 要求是如果一个信号在 shell 启动时被忽略,你就无法忽略它,所以你就完蛋了。
在这里,您可以使用没有那些烦人的“功能”(至少在当前版本中)的来zsh
代替。sh
无论如何,shell 中的信号处理是最不可靠和最便携的方面之一。您会发现 shell 之间以及同一 shell 的不同版本之间的行为差异很大。如果你打算尝试做任何不平凡的事情,就要做好被严重拉扯和挠头的准备。
我建议使用不同的语言,这样您可以更好地控制发生的情况。
另外,我不会盲目地处理所有可能的信号,只会处理您期望收到并知道如何处理的信号。例如,捕获 SIGCHLD(shell 本身对此感兴趣,因为它的工作是生成进程并处理其终止)可能不会执行您想要的操作。