我对 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 只会杀死cmd1
和cmd2
,但不会杀死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 秒,然后就会终止。