
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 echo
e 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_eof
comando na sua pergunta.
Outra opção:
( echo some stuff; cat more_stuff.txt ) >P
ou
{ echo some stuff; cat more_stuff.txt; } >P