我有用于处理数据的 Bash 脚本,这些数据是通过管道从另一个进程发送的。
我正在尝试添加一个在满足特定条件后导致和退出的功能,其简化表示为:
( while true; do date; sleep 1; done ) | ( for ((i = 0; i < 3; i++)); do read -r line; echo LINE: $line; sleep 1; done; exit 1 )
在实际情况下:
- 管道之后的命令包含在脚本中(并被脚本替换);
- 管道之前的命令是二进制可执行文件,我无法控制它的内部。
我也尝试关闭标准输入:
( while true; do date; sleep 1; done ) | ( for ((i = 0; i < 3; i++)); do read -r line; echo LINE: $line; sleep 1; done; exec 0<&- )
但是,当条件满足时,什么都不会发送到 stdout,但左边的程序仍然运行。
我怎样才能完成任务?
您的管道不退出的原因是该
exit 1
语句仅终止右侧子外壳。在右侧退出后,
date
用于生成数据的命令将开始失败,因为它无法将其输出写入任何地方(它会被PIPE
信号杀死)。您没有测试 的退出状态date
,因此您看不到这一点。将左侧重写为
或作为
将使整个管道按预期运行。
这表明您在管道左侧的数据生成二进制文件没有检查写入是否成功(并且它也可能忽略
PIPE
信号)。在右侧子shell 中关闭标准输入将无济于事(无论如何,当您退出该子shell 时,这已经完成)。这是生成数据的程序中的一个错误。
你怎么能解决这个问题?
一种方法是使用命名管道。这将允许您获取数据生成进程的 PID,稍后您可以使用它来杀死它:
如果程序忽略了
PIPE
信号,它很可能忽略了其他信号,因此您必须先尝试发送默认信号,TERM
如果这不起作用,请尝试INT
等等。