当管道用于输入重定向子 shell 时,Ctrl-c 会终止 shell

当管道用于输入重定向子 shell 时,Ctrl-c 会终止 shell

如果我运行如下命令:

cat <(echo 1 | pv) | pv
cat <(echo 1 | pv) | less
cat <(echo 1 | pv) | cat

该命令似乎会永远运行。输入^C(SIGINT) 会杀死整个 shell,而不仅仅是执行的命令。为什么会这样呢?


ps xf最小情况下另一个 shell 的相关输出cat <(pv) | less

Ss  /bin/bash
S+   \_ cat /dev/fd/XX
S    |   \_ /bin/bash
T    |       \_ pv
S+   \_ less

打开这些文件描述符:

巴什

0 -> /dev/pts/YY
1 -> /dev/pts/YY
2 -> /dev/pts/YY
255 -> /dev/pts/YY

猫 /dev/fd/ZZ

0 -> /dev/pts/YY
1 -> pipe:[RRRRRRRR]
2 -> /dev/pts/YY
3 -> pipe:[QQQQQQQQ]
ZZ -> pipe:[QQQQQQQQ]

巴什

0 -> /dev/pts/YY
1 -> pipe:[QQQQQQQQ]
2 -> /dev/pts/YY
255 -> /dev/pts/YY

光伏发电

0 -> /dev/pts/YY
1 -> pipe:[QQQQQQQQ]
2 -> /dev/pts/YY

较少的

0 -> pipe:[RRRRRRRR]
1 -> /dev/pts/YY
2 -> /dev/pts/YY
3 -> /dev/tty

使用原始示例(当不是 bash 内置程序而是另一个程序cat <(echo 1 | pv) | less时,也会发生这种情况,例如:echodd if=/dev/zero bs=1 count=1

Ss   /bin/bash
S+    \_ cat /dev/fd/63
S     |   \_ /bin/bash
T     |       \_ pv
S+    \_ less

巴什

0 -> /dev/pts/18
1 -> /dev/pts/18
2 -> /dev/pts/18
255 -> /dev/pts/18

猫 /dev/fd/63

0 -> /dev/pts/18
1 -> pipe:[36932796]
2 -> /dev/pts/18
3 -> pipe:[36929317]
63 -> pipe:[36929317]

巴什

0 -> /dev/pts/18
1 -> pipe:[36929317]
2 -> /dev/pts/18
255 -> /dev/pts/18

光伏发电

0 -> pipe:[36930391]
1 -> pipe:[36929317]
2 -> /dev/pts/18

较少的

0 -> pipe:[36932796]
1 -> /dev/pts/18
2 -> /dev/pts/18
3 -> /dev/tty

答案1

发生这种情况是因为该<(过程)没有得到适当的作业控制——它只是被分叉并忘记了。大多数时候这并不重要,因为几乎该进程一诞生就被放置在一个单独的进程组中并处于后台。为了立即的shell 需要打开该进程的输入和输出,但是,这是 tty 的前台进程组,因此容易受到 SIGINT 的影响 - 除非它像交互式 shell 通常那样被捕获或忽略。

但问题是:管道出现了僵局。当父进程尝试打开该进程的输出时,管道会阻塞。它永远没有机会改变进程组和所有其他的,因为当你CTRL+C前台组被杀死 - 它被发送 SIGINT - 当前台组死亡并且父组无法恢复控制时,因为它仍然被管道阻塞,终端会发送一个 HUP,因为家里没人。卡布姆

您首先需要一个编写器,然后为您打开的每个管道提供一个读取器,然后才能打开另一个管道。

相关内容