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

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

Eu tenho um programa que sai automaticamente ao ler um EOF em um determinado fluxo (no caso a seguir, stdin).
Agora quero fazer um script de shell, que crie um pipe nomeado e conecte o stdin do programa a ele. Então o script escreve no pipevárias vezesusando echoe cat(e outras ferramentas que geram automaticamente um EOF quando saem). O problema que estou enfrentando é que, quando o primeiro echoé feito, ele envia um EOF para o pipe e faz o programa sair. Se eu usar algo assim tail -f, não poderei enviar um EOF quando pretendo sair do programa. Estou pesquisando uma solução equilibrada, mas sem sucesso.
Já descobri como evitar EOFs e como enviar um EOF manualmente, mas não consigo 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

Responder1

Como outros indicaram, o leitor de um pipe recebe EOF quando não há mais escritores. Portanto, a solução é garantir que sempre haja um redator mantendo-o aberto. Esse escritor não precisa enviar nada, apenas mantenha-o aberto.

Como você está usando um script de shell, a solução mais simples é dizer ao shell para abrir o canal para gravação. E feche-o 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 arquivo 3 será automaticamente fechado (e assim o leitor receberá EOF) quando o script for encerrado. Além da conveniência, isso também fornece uma espécie de segurança se o script terminar de alguma forma mais cedo.

Responder2

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

mkfifo P
while sleep 1; do :; done >P &
P_writer_pid=$!
send_eof_to_P () {
  kill $P_writer_pid
}

Responder3

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

Se você tiver a capacidade de modificar o comportamento do seu programa, faça a leitura em um loop infinito (uma iteração dura até o EOF) e envie uma string de comando específica que significa "hora de encerrar". Enviar essa string seria a tarefa do send_eofcomando na sua pergunta.

Outra opção:

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

ou

{ echo some stuff; cat more_stuff.txt; } >P

informação relacionada