如何仅终止当前进程并继续 shell 管道?

如何仅终止当前进程并继续 shell 管道?

我对 Bash 有 2 个相关的疑问。

(Q1)考虑tail -f SomeFile | wc,一个虚构的命令行,其中tail用于模拟长时间运行的命令(C1),不时产生一些输出,并wc用于模拟处理该输出的命令(C2)当C1结束时。等待了很长一段时间(比平时更长)后,我想看看到目前为止已经生成了什么输出,所以我希望 C1 终止。但是按 Ctrl-C 将会终止整个管道。我怎样才能只杀死C1(或者甚至是C1的一个组件,如果它本身就是一个复合命令)?
如果 C1 循环遍历许多文件并 grep 一些文本,但有一个文件来自某个挂起的 nfs 服务器,那么我只想终止该 grep 进程。

(for F in A B C D E ; do grep sometext $F ; done) | wc

这里 Ctrl-C 将终止整个命令行,但我只想终止当前正在运行(或挂起)的进程并继续处理剩余的文件。

我的一个解决方案是打开一个新连接,获取 ps 输出,然后“杀死”它。我想知道 Bash 本身是否有解决方案,例如某些奇怪的组合键仅杀死当前进程?

(Q2)在尝试为这个问题举例时,我创建了这个命令行,这里,如果我按下 Ctrl-C,我会得到一行额外的输出,如下所示:

# echo `ping 127.0.0.1` | wc
^C

#

当不使用反引号 (``) 时,不会出现多余的行:

# tail -f SomeFile | wc
^C
#

我的想法是否正确,因为反引号(``)是由 bash 本身处理的,并且当子进程被终止时,它仍然被视为“空输出”,因此被打印为额外的行?

答案1

bash你可以运行:

cmd1 | cmd2 | (trap '' INT; cmd3)

Control-C 只会杀死cmd1cmd2,但不会杀死cmd3

例子:

$ while sleep .1; do echo -n 1; done | (trap '' INT; tr 1 2)
^C222222222
$ while sleep .1; do echo -n 1; done | tr 1 2
^C

这利用了“忽略”信号处理由子进程继承的事实——这trap '' INT也会影响tr命令。但当然,某些命令会安装自己的SIGINT处理程序,这将打破这个假设。

ksh93不幸的是,由于一个愚蠢的错误,这不起作用。解决方法可能是:

ksh93$ while sleep .1; do echo -n 1; done | sh -c 'trap "" INT; exec tr 1 2'
^C222222222ksh93$

答案2

该命令stty -a将显示所有键盘快捷键。唯一映射的信号是 Ctrl-C (SIGINT)、Ctrl-\ (SIGQUIT) 和 Ctrl-Z (SIGSUSP)。没有与其他信号的绑定。

我会使用您自己所说的解决方案:单独的 shell、ps输出和kill您需要杀死的进程。

对于你的第二个问题,这不是因为重音符号(``),而是因为echo.试试这个例子:

# echo `sleep 10` | wc
^C

# `sleep 10` | wc
^C
# sleep `echo "10"` | wc
^C
#

答案3

使用以下命令进行测试,效果很好

tail -f /var/log/kern.log & read -t 10 ;kill $!

上面的命令只会运行 10 秒,然后就会终止。

相关内容