Problema com os tubos. O tubo termina quando o leitor terminar

6

Estou no OSX, usando o bash, tentando entender os canais. Eu gostaria de deixar um programa se comunicar em duas direções com um shell bash. Eu quero configurar isso de tal forma que este é sempre o mesmo shell, para que eu possa fazer o cd para algum diretório e o bash vai lembrar (ao invés de usar um novo shell bash o tempo todo).

O que eu tentei até agora é isso. De um novo terminal (A), faça

mkdir /tmp/IOdir
cd /tmp/IOdir
mkfifo pToB
mkfifo bToP
tail -f -1 pToB | bash >> bToP

Então, para testar esta conexão, eu posso fazer, a partir de um novo terminal (B)

cd /tmp/IOdir
echo echo hello > pToB

e de um terceiro terminal (C)

cd /tmp/IOdir
(read myline &&  echo $myline) < bToP

Isso se comporta como eu quero. O mesmo shell bash permanece ativo e a saída passa do outro lado. Chame esse estado de coisas X, para que eu possa me referir mais tarde a ele.

A partir do estado X

No entanto, agora, a partir desse estado X, não podemos fazer a mesma coisa novamente. Isto é, se fizermos do terminal (B)

echo echo hello > pToB

e depois do terminal C

(read myline &&  echo $myline) < bToP

Então nada aparece no terminal C. Além disso, se fizermos novamente, a partir do terminal B

echo echo hello > pToB

O shell bash se fecha.

O que eu poderia ter feito no estado X primeiro era do terminal C

(read myline &&  echo $myline) < bToP

e depois do terminal B

echo echo hello > pToB

Nesse caso, oi vem pelo terminal C, e parece que estamos no estado X novamente. Então podemos basicamente repetir isso para sempre. Agora isso pode parecer suficiente para comunicação bidirecional, mas meu programa é tal que se ele solicitar uma nova linha como essa

(read myline &&  echo $myline)

e não há nenhuma nova linha, ele irá "travar" (assim como bash, na verdade eu pretendo usar uma chamada para bash no programa). Portanto, não é possível enviar a entrada para o pToB depois disso e não há nada que eu possa fazer.

Perguntas

Existe uma maneira de configurar isso sem fazer muita programação em C? Existe uma maneira de fazer isso com mais elegância sem usar dois pipes nomeados? O que está causando o fechamento do pipe em um cenário e não no outro?

Edições

De esta página na wikipedia , temos

Full-duplex (two-way) communication normally requires two anonymous pipes.

Por um lado, parece que pelo menos eu tenho o número certo de tubos. Por outro lado, estou usando pipes nomeados, não anônimos. Então, talvez isso seja difícil / impossível.

Além disso mkfifo fonte gnu / linux é provavelmente definido em termos de mknod fonte gnu / linux , que é também um comando unix. Mas não tenho certeza se muito pode ser aprendido com isso.

Aqui é uma introdução aos pipes em C, incluindo a fonte linux do pipe. Talvez isso possa nos dizer por que um cano fica fechado, se é isso que acontece.

Aqui é uma questão relacionada sobre como evitar que fifos sejam fechados. Eu tentei amarrar os canos para os processos de dormir em segundo plano, como foi feito em uma resposta, mas isso não ajudou.

    
por Trooper 04.07.2013 / 17:03

2 respostas

2

Quanto à causa, use strace .

tail -f | strace bash >> foo

O segundo echo echo hello > pToB me dá isso:

rt_sigprocmask(SIG_BLOCK, NULL, [], 8)  = 0
read(0, "e", 1)                         = 1
read(0, "c", 1)                         = 1
read(0, "h", 1)                         = 1
read(0, "o", 1)                         = 1
read(0, " ", 1)                         = 1
read(0, "h", 1)                         = 1
read(0, "e", 1)                         = 1
read(0, "l", 1)                         = 1
read(0, "l", 1)                         = 1
read(0, "o", 1)                         = 1
read(0, "\n", 1)                        = 1
write(1, "hello\n", 6)                  = -1 EPIPE (Broken pipe)
--- SIGPIPE {si_signo=SIGPIPE, si_code=SI_USER, si_pid=3299, si_uid=1000} ---
+++ killed by SIGPIPE +++

Então, na segunda vez que ele tenta escrever hello \ n, ele recebe um erro de pipe quebrado; é por isso que você não pode ler oi (nunca foi escrito), e o bash quits então é o fim disso.

Você teria que usar algo que mantenha o tubo aberto, eu acho.

Que tal isso?

(while read myline; do echo $myline; done) < pToP

Para mais informações básicas, man 7 pipe pode ser relevante, descreve os vários casos de erro em torno dos pipes.

    
por 04.07.2013 / 22:53
1

Como um adendo à resposta do frostschutz, considere a seguinte tabela

AprimeiravezquetentamosenviarooláparaobToP,eleficabloqueadoatéquetambémhajaumleitorparaofifo.Nasegundavezquenós,oleitorenviadevoltaumsinalSIGPIPE,queterminaobash.Mesmosepudéssemosignorarisso,provavelmenteteríamosoerroEPIPEdepoisdisso.

Achoqueoqueestoutentandofazeréimpossível.Meuaplicativonãopode"ler e escrever ao mesmo tempo". Acho que vou ter que fazer um programa intermediário capaz de manter os dois lados do tubo abertos.

    
por 05.07.2013 / 11:42

Tags