如果在 bash 中我在命令行上运行a | b | c | d
然后按 ^C,哪个进程得到信号?
简而言之,他们都这样做。
设置管道时,shell 会创建一个进程组。^C 被内核的行规则解释为用户中断当前在前台运行的进程组的请求。向进程组发送信号(如 SIGINT
)会自动将信号传递到组中的所有进程。
我更喜欢实验:
#!/bin/bash
# FILE /tmp/bla.sh
# trap ctrl-c and call ctrl_c()
trap ctrl_c INT
MY_ID=$1 # Identifier for messages
function ctrl_c() {
echo >&2 "GOODBYE $MY_ID"
exit
}
# This will continue until interrupted, e.g. if the input/output get closed
cat
# If we somehow got to the end
echo >&2 "grace $MY_ID"
链接它们,运行和破坏它们
nitz@mars:~$ /tmp/bla.sh 1 | /tmp/bla.sh 2
^CGOODBYE 2
GOODBYE 1
0
如您所见,两次执行都得到了中断信号,这意味着它们都被杀死了。此外,他们输出他们被杀的顺序是随机的,例如:
nitz@mars:~$ /tmp/bla.sh 1 | /tmp/bla.sh 2 | /tmp/bla.sh 3 | /tmp/bla.sh 4
^CGOODBYE 2
GOODBYE 4
GOODBYE 1
GOODBYE 3
基于@Nitz的优秀(我也喜欢实验)答案,如果您不希望所有进程都获得信号,您可以使用 bash 进程替换(感谢这个答案)。
以下示例显示1
进程确实会获取信号,但2
和3
进程不会。
$ /tmp/bla.sh 1 > >(/tmp/bla.sh 2 | /tmp/bla.sh 3)
^CGOODBYE 1
grace 2
grace 3
您也可以重定向 stderr,它仍然有效。
我的用例是尝试过滤作为 docker 容器入口点的命令的输出,但我不想弄乱主进程的信号处理。
编辑:某些命令组合似乎存在一些缓冲问题,但我不明白为什么。因此,这可能不适合您的用例。
# no buffering issues here
(echo 1; sleep 1; echo 2; sleep 2; echo 3) > >(cat)
(echo 1; sleep 1; echo 2; sleep 2; echo 3) > >(cat | cat | cat)
(echo 1; sleep 1; echo 2; sleep 2; echo 3) > >(cat | grep -v blah)
# no output until original command finishes for this *shrugs*
(echo 1; sleep 1; echo 2; sleep 2; echo 3) > >(grep -v blah | cat)