Evitar EOFs automáticos para um pipe nomeado e enviar um EOF quando eu quiser

8

Eu tenho um programa que sai automaticamente ao ler um EOF em um determinado fluxo (no seguinte caso, stdin).
Agora eu quero fazer um script de shell, que cria um pipe nomeado e conecta o stdin do programa a ele. Em seguida, o script grava no canal várias vezes usando echo e cat (e outras ferramentas que geram automaticamente um EOF quando saem). O problema que estou enfrentando é, quando o primeiro echo é feito, ele envia um EOF para o pipe e faz o programa sair. Se eu usar algo como tail -f , não posso enviar um EOF quando pretendo sair do programa. Estou pesquisando uma solução equilibrada, mas sem sucesso.
Eu já encontrei tanto como evitar EOFs e como enviar manualmente um EOF, mas não posso combiná-los. Existe alguma dica?

#!/bin/sh
mkfifo P
program < P & : # Run in background
# < P tail -n +1 -f | program
echo some stuff > P # Prevent EOF?
cat more_stuff.txt > P # Prevent EOF?
send_eof > P # How can I do this?
# fg
    
por iBug 20.05.2017 / 12:25

3 respostas

8

Como outros indicaram, o leitor de um pipe recebe EOF uma vez que não há gravadores restantes. Portanto, a solução é garantir que haja sempre um gravador mantendo-o aberto. Esse escritor não precisa enviar nada, apenas abra-o.

Como você está usando um script de shell, a solução mais simples é informar ao shell para abrir o pipe para gravação. E depois feche quando terminar.

#!/bin/sh
mkfifo P
exec 3>P # open file descriptor 3 writing to the pipe
program < P
# < P tail -n +1 -f | program
echo some stuff > P
cat more_stuff.txt > P
exec 3>&- # close file descriptor 3

Observe que, se você omitir a última linha, o descritor de arquivos 3 será automaticamente fechado (e, assim, o leitor receberá EOF) quando o script sair. Além da conveniência, isso também fornece uma espécie de segurança se o script terminar de alguma forma antes.

    
por 20.05.2017 / 19:00
2

Um pipe recebe EOF quando o último autor desaparece. Para evitar isso, certifique-se de que há sempre um gravador (um processo que tem o canal aberto para gravação, mas que na verdade não escreve nada). Para enviar o EOF, faça esse escritor de reserva ir embora.

mkfifo P
while sleep 1; do :; done >P &
P_writer_pid=$!
send_eof_to_P () {
  kill $P_writer_pid
}
    
por 20.05.2017 / 15:36
0

Não há como o programa distinguir entre um EOF que significa "é hora de sair" e um EOF que significa "um escritor está pronto, mas pode haver mais informações de outra pessoa".

Se você tiver a capacidade de modificar o comportamento de seu programa, faça a leitura em um loop infinito (uma iteração dura até EOF) e envie uma sequência de comandos específica que significa "tempo para sair". Enviar essa sequência seria a tarefa do comando send_eof em sua pergunta.

Outra opção:

( echo some stuff; cat more_stuff.txt ) >P

ou

{ echo some stuff; cat more_stuff.txt; } >P
    
por 20.05.2017 / 15:40