【发布时间】:2013-12-30 06:55:07
【问题描述】:
谁能告诉我为什么下面的bash语句不能被Ctrl+c正确终止?
$( { ( tail -fn0 /tmp/a.txt & )| while read line; do echo $line; done } 3>&1 )
我运行这条语句,然后启动两个bash进程和一个tail进程(从ps auxf得到),然后输入Ctrl+c,它不会退出到bash 提示符,此时我看到两个bash 进程停止,而tail 仍在运行,然后我在/tmp/a.txt 中输入一些内容,然后我们可以进入bash 提示符。
我想要的是,输入Ctrl+c,然后直接退出bash提示符,没有任何相关流程。
如果有人解释了这个语句的确切过程,那就更感激了,比如管道导致 bash 分叉,某些东西重定向到某个地方等等。
2014 年 10 月 9 日更新:
这里提供一些更新,以防它对您有用。 我的采用解决方案与 2 个因素相似:
-
使用 tmp pid 文件
( tail -Fn0 ${monitor_file} & echo "$!" >${tail_pid} ) | \ while IFS= read -r line; do xxxx done 使用陷阱如:
trap "rm ${tail_pid} 2>/dev/null; kill 0 2>/dev/null; exit;" INT TERM杀死相关进程并删除剩余文件。
请注意,kill 0 2 是特定于 bash 的,0 表示当前进程组中的所有进程。
这个解决方案使用了一个 tmp pid 文件,而我仍然期待其他没有 tmp pid 文件的解决方案。
【问题讨论】:
-
你为什么用
$(...)运行它?那是用于命令替换。 -
"tail -fn0 /tmp/a.txt &" 在后台启动一个新进程(由于&),所以不受主进程的ctrl+c影响。
-
我想知道这种行为是否与 bash 处理管道和收集管道中每个进程的状态的方式有关。传统上,只有管道中的最后一个进程是 shell 的子进程,所以当最后一个进程退出时,其他进程就没有父进程了。但是,由于
bash等待(或可以等待)所有子进程(因此状态被收集在PIPESTATUS数组中),这意味着“管道”在所有进程终止之前不会结束,并且tail -f在向管道写入内容后,直到收到 SIGPIPE 信号后才会终止。 -
你可能有一些运气使用
trap(用于中断信号)来杀死尾巴,你可能需要保存 PID,这可能很棘手......(pgrep -f "tail -fn0 /tmp/a.txt"可以工作,但是如果多个实例正在运行,则会出现问题...)
标签: bash shell terminate sigint