【问题标题】:Cannot terminate a shell command with Ctrl+c无法使用 Ctrl+c 终止 shell 命令
【发布时间】: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 个因素相似:

  1. 使用 tmp pid 文件

    ( tail -Fn0 ${monitor_file} & echo "$!" >${tail_pid} ) | \
    while IFS= read -r line; do 
        xxxx
    done 
    
  2. 使用陷阱如: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


【解决方案1】:

它可以捕获INT 信号(由Ctrl-C 发送)以杀死tail 进程。

$( r=$RANDOM; trap '{ kill $(cat /tmp/pid$r.pid);rm /tmp/pid$r.pid;exit; }' SIGINT EXIT; { ( tail -fn0 /tmp/a.txt & echo $! > /tmp/pid$r.pid  )| while read line; do echo $line; done } 3>&1 )

(我在 PID 文件名上使用随机值,至少大部分情况下允许多个实例运行)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-15
    • 1970-01-01
    • 1970-01-01
    • 2019-08-06
    • 2018-07-31
    相关资源
    最近更新 更多