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


12

Eu tenho um programa que sai automaticamente após a leitura de um EOF em um determinado fluxo (no caso a seguir, stdin).
Agora eu quero criar um script de shell, que crie um pipe nomeado e conecte o stdin do programa a ele. Em seguida, o script grava no canal várias vezes usando echoe cat(e outras ferramentas que geram automaticamente um EOF quando saem). O problema que estou enfrentando é que, quando o primeiro echoé concluído, ele envia um EOF ao canal e faz com que o programa saia. 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á descobri como impedir EOFs e como enviar um EOF manualmente, 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

Respostas:


13

Como outros indicaram, o leitor de um tubo recebe EOF quando não houver mais escritores. Portanto, a solução é garantir que haja sempre um escritor segurando-o aberto. Aquele 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 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 arquivo 3 será automaticamente fechado (e, portanto, o leitor receberá EOF) quando o script sair. Além da conveniência, isso também oferece uma espécie de segurança se o script terminar de alguma forma mais cedo.


2
essa exec 3>Pcausa está pendurada no bash, por quê?
1055 Wang Wang

@ Wang Não deveria. Se isso acontecer, você provavelmente não está fazendo a mesma coisa que o código POC na pergunta. A única razão pela qual posso pensar que isso seria bloqueado é se você estiver fazendo algo como exec 2>P, e você tiver o modo de rastreamento ativado ( set -x), no qual o bash gravará no canal, mas não há leitor, pois ele bloqueia a espera por algo para ler.
Patrick

1
@ Wang @ Patrick De fato também exec 3>Ptrava na minha máquina. Isso ocorre porque não há leitura de processo P. Assim, a solução foi trocar linhas exec 3>Pe program < P &(adicionando o e comercial para que o programa seja executado em segundo plano).
macieksk

2

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

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

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ê tem 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 a ele uma sequência de comandos específica que significa "hora de sair". 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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.