Ctrl-c mata o shell quando o pipeline é usado no subshell de redirecionamento de entrada

4

Se eu executar um comando como:

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

O comando parece ser executado para sempre. Digitar ^C (SIGINT) mata todo o shell em vez de apenas os comandos executados. Por que isso acontece?

Saída relevante de ps xf de outro shell no caso mínimo cat <(pv) | less :

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

Com esses descritores de arquivos abertos:

bash

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

cat / dev / fd / ZZ

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

bash

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

pv

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

menos

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

Usando o exemplo original, cat <(echo 1 | pv) | less (isso também acontece quando echo não é um bash interno, mas outro programa como dd if=/dev/zero bs=1 count=1 :

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

bash

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

cat / dev / fd / 63

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

bash

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

pv

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

menos

0 -> pipe:[36932796]
1 -> /dev/pts/18
2 -> /dev/pts/18
3 -> /dev/tty
    
por arcyqwerty 30.12.2015 / 20:26

1 resposta

3

Isso acontece porque o <( process ) não é adequadamente controlado pelo trabalho - é apenas bifurcado e esquecido. Isso não importa na maior parte do tempo, porque quase assim que nasce, o processo é colocado em um grupo de processos separado e em segundo plano. Para o instante que o shell requer para abrir entrada e saída para esse processo, no entanto, esse é o grupo de processo em primeiro plano e, como tal, vulnerável a SIGINT - a menos que seja preso ou ignorado como seu shell interativo geralmente faz.

A coisa é, no entanto: você tem um impasse de pipe lá. Quando o pai tenta abrir a saída para esse processo, bloqueie os blocos. Ele nunca tem a chance de alterar o grupo de processos e todo o restante porque quando você CTRL+C o grupo de primeiro plano é morto - é enviado SIGINT - e quando o grupo de primeiro plano morre e o pai não pode retomar o controle porque ainda está bloqueado em um tubo, o terminal envia um HUP porque não há ninguém em casa. kaboom

Você precisa primeiro de um escritor, depois de um leitor para cada canal que abrir antes de abrir outro.

    
por 30.12.2015 / 21:34