passando stdin para processar A e processo B (invocado por A)

2

Suponha que o processo interativo A lê a entrada do terminal e ocasionalmente gera o processo B, que também lê a entrada do terminal. Por exemplo, A lê um número e passa o controle para B, que lê o que quer que seja.

Editar: A e B não estão sendo executados simultaneamente, no cenário específico A invoca B usando system() .

É possível redirecionar stdin de forma que A e B leiam a partir de stdin?

Experiências mostram que um ingênuo

echo -e '123\nxyzzy' | A

onde 123 deve ser lido por A e xyzzy por B não funciona.

    
por countermode 04.09.2016 / 00:30

2 respostas

3

É possível alimentar a entrada para vários processos. Quando vários processos estão lendo do mesmo canal ou terminal, cada byte vai para um dos processos, o que quer que aconteça ler primeiro esse byte em particular. Quando apenas um processo está lendo ativamente, ele recebe a entrada. Quando vários processos estão lendo ativamente ao mesmo tempo, qual recebe a entrada é imprevisível.

Você está entrando em conflito com o armazenamento em buffer . A maioria dos programas, evidentemente incluindo A, lê um buffer inteiro de cada vez - normalmente algumas centenas de bytes ou alguns kilobytes - e os armazena em sua própria memória até processá-los. Isso é muito mais rápido do que ler um byte de cada vez. Mas neste cenário, isso significa que A lê mais do que a parte que irá processar antes de chamar B, então a entrada significada para B já é consumida por A quando B começa.

Se você pode fazer B ler de uma fonte diferente, é claro que é uma solução.

Se você tiver controle sobre como A é executado, tente stdbuf de GNU coreutils . Ele conecta-se às chamadas da biblioteca para fazer com que o processo leia um byte de cada vez. Isso funciona com a maioria dos programas, mas não todos: ele não funciona com executáveis vinculados estaticamente e não funciona se o programa usa um método de buffer diferente da biblioteca padrão (stdio).

… | stdbuf -i 1 A

Como alternativa, tente ler em um arquivo comum. Quando A leu a entrada de um cano ou terminal, não pode colocá-lo de volta. Mas quando é lido a partir de um arquivo normal, ele pode retroceder a posição de leitura antes de chamar B. É assim que o read shell embutido se comporta, por exemplo. Não há garantia de que o programa em particular A o faça, na verdade, não é um comportamento muito comum, mas se isso acontecer, é uma solução simples.

Se isso não funcionar, ou se você não tiver controle sobre como A é executado, será necessário organizar o tempo da entrada para que a parte destinada para B não esteja presente até que B seja iniciado. Como fazer isso depende de como você pode detectar que o B foi iniciado. Uma solução possível, mas frágil, é colocar um atraso:

{ echo 123; sleep 1; echo xyzzy; } | A

Isso só funciona se A chamar B dentro de 1 segundo, o que é frágil. Uma solução mais confiável é detectar a saída produzida por A (ou B). Esse é o tipo de problema que espera foi projetado para resolver. Por exemplo, se B exibir algum tipo de prompt como B> :

#!/usr/bin/expect -f
spawn A
send "123\r"
expect "B>"
send "xyzzy\r"
    
por 04.09.2016 / 01:23
0

É um problema de buffer. O processo A, usando stdio, lê um pedaço de stdin, de modo que a parte destinada a B já desapareceu quando B recebe o controle. Uma solução possível é preencher a entrada assim:

python -c 'print("123" + "\n"*4093 + "xyzzy\n")' | A

funciona como esperado (o tamanho real do buffer - aqui 4096 - pode precisar de ajuste).

    
por 04.09.2016 / 00:47