Se você se livrar do material de encerramento e desligamento (o que é inseguro e você pode, em um caso extremo, mas não insondável, quando child.py morre antes que a subcamada (head -n 1 shutdown; kill -9 $parent) & acabe kill -9 ing algum processo inocente ),
então child.py não será encerrado porque seu parent.py não está se comportando como um bom cidadão do UNIX.
O subprocesso cat std_out & terá terminado quando você enviar a mensagem quit , porque o gravador de std_out é child_original.py , que termina ao receber quit , quando fecha seu stdout , que é o std_out pipe e que close fará o subprocesso cat terminar.
O cat > std_in não está terminando porque está lendo um pipe originado no processo parent.py e o processo parent.py não se preocupou em fechar esse canal. Se assim fosse, cat > stdin_in e consequentemente todo o child.py terminaria sozinho e você não precisaria do pipe de desligamento ou da killing part (matar um processo que não é seu filho no UNIX é sempre um potencial de segurança buraco se uma condição de corrida causada devido à reciclagem rápida do PID ocorrer.)
Processos na extremidade direita de um pipeline geralmente só terminam quando eles terminam de ler seu stdin, mas como você não está fechando isso ( child.stdin ), você está dizendo implicitamente ao processo filho "wait, i have mais entrada para você "e então você vai matá-lo, porque ele espera por mais entrada de você como deveria.
Em suma, faça com que parent.py se comporte de maneira razoável:
from __future__ import print_function
from subprocess import Popen, PIPE
import os
child = Popen('./child.py', stdin=PIPE, stdout=PIPE)
for letter in 'abcde':
print('Parent writes to child: ', letter)
child.stdin.write(letter+'\n')
child.stdin.flush()
response = child.stdout.readline()
print('Response from the child:', response)
assert response.rstrip() == letter.upper(), 'Wrong response'
child.stdin.write('quit\n')
child.stdin.flush()
child.stdin.close()
print('Waiting for the child to terminate...')
child.wait()
print('Done!')
E o seu child.py pode ser tão simples quanto
#!/bin/sh
cat std_out &
cat > std_in
wait #basically to assert that cat std_out has finished at this point
(Note que me livrei daquelas chamadas do fd dup porque de outra forma você precisaria fechar o child.stdin e o child_stdin duplicado).
Como parent.py opera de maneira orientada por linhas, gnu cat é sem buffer (como mikeserv apontou) e child_original.py opera de maneira orientada a linhas, você efetivamente tem a coisa toda com buffer de linha. / p>
Observação no Cat: O Unbufferred pode não ser o termo mais sortudo, pois o gnu cat usa um buffer. O que ele não faz é tentar obter todo o buffer antes de escrever as coisas (ao contrário do stdio). Basicamente, ele faz solicitações de leitura ao sistema operacional para um tamanho específico (seu tamanho de buffer) e grava o que recebe sem esperá-lo para obter uma linha inteira ou o buffer inteiro. ( read (2) pode ser preguiçoso e dar a você apenas o que ele pode lhe dar no momento em vez do todo buffer que você pediu.)
(Você pode inspecionar o código-fonte em link ; safe_read (usado em vez de read puro) está no submódulo gnulib e é um wrapper muito simples em torno de read (2 ) que abstrai EINTR (veja a man page)).