考虑一个自定义命令行软件(例如 loopHelloWorld),它检测 ctrl+C 以实现良好的关闭。如何在不丢失的情况下传递答案Ctrl+C
?
$ loopHelloWorld
- Ctrl+C to nicely shutdown
但是使用管道,管道会在没有良好关闭的情况下杀死软件
$ loopHelloWorld |
while IFS= read -r line; do
echo "$line"
done
例子
ping example.com |
while IFS= read -r line; do
echo "$line"
done
Ctrl+C导致将 SIGINT 发送到管道中的所有进程(因为它们都在与交互式 shell 的前台作业对应的同一进程组中运行)。
所以在:
正在运行的进程
loopHelloWorld
和运行运行while
循环的子shell 的进程都将获得SIGINT
.如果
loopHelloWorld
将Ctrl+C to nicely shutdown
消息写入其标准输出,它也将被写入管道。如果那是在另一端的子shell 已经死亡之后,那么loopHelloWorld
也会收到一个 SIGPIPE,您需要处理它。在这里,您应该将该消息写入 stderr,因为它不是您的命令的正常输出(但不适用于
ping
示例)。然后它不会通过管道。或者您可以让运行 while 循环的子外壳忽略 SIGINT,以便在 SIGINT
loopHelloWorld
之后继续读取输出:但是,当您按 时,这将导致管道的退出状态为 0 Ctrl+C。
该特定示例的另一个选项是使用
zsh
orksh93
代替bash
. 在这些 shell 中,while
循环将在主 shell 进程中运行,因此不会受到 SIGINT 的影响。loopHelloWorld | cat
尽管在前台进程组中的位置cat
和运行,这无济于事。loopHelloWorld
使用陷阱: