Pipe nomeado em buffer sem bloqueio?

20

Estou procurando por algo que suspeito que não exista: Um pipe nomeado em buffer sem bloqueio (fifo) para uso na linha de comando. Existe uma coisa dessas?

Aqui está o caso de uso: Suponha que eu tenha um processo que demore muito tempo em segundo plano e forneça muita saída para stdout. Eu realmente não me importo com a saída e não quero armazená-la (talvez não tenha espaço suficiente para isso), mas gostaria de "aparecer" periodicamente e seguir o que está fazendo, depois desistir novamente e deixe-o fazer o seu trabalho. Então, eu gostaria de redirecionar sua saída para esse pipe nomeado, com buffer e sem bloqueio teórico, e depois usá-lo periodicamente.

Então, basicamente, eu quero começar assim ( 10Msendo o tamanho do buffer):

mkmagicfifo magicfifo 10M
spewingprocess > magicfifo &

... e periodicamente aparecer para ver o que está acontecendo ...

tail -f magicfifo

... sem magicfifo armazenar toda a saída (portanto, não é um arquivo normal) e sem bloquear o processo de vomitar quando é preenchido e não é aproveitado (portanto, não é um pipe nomeado normal).

Não acho que as soluções envolvam tailou pruneo façam (bem, consigo pensar em uma solução alternativa tail), porque tailainda exigiria que eu armazenasse todos os dados em algum lugar (se eu quiser entrar e sair de olhar para eles), e prunetem que reescrever o arquivo, presumivelmente (admito que não tentei / provei isso) interrompendo o redirecionamento do processo gerando toda a saída.

Eu espero que eu possa escrever algum utilitário para fazer isso, mas o * nix tem tantos aspectos interessantes de arquivos e pipes e outros, eu simplesmente não posso deixar de pensar que isso existe e simplesmente não sei sobre isso.

Então: existe tal coisa e, em caso afirmativo, o que é?

TJ Crowder
fonte
1
O que você está descrevendo é um "buffer de anel" ou "buffer circular". Não conheço nenhuma ferramenta de linha de comando para manter uma coisa dessas, embora seja trivial criar.
Shawn J. Goff
2
Veja as soluções descritas em "Linux non-blocking fifo (registro on demand)", stackoverflow.com/questions/7360473/… .
1
Parece que este foi resolvido em StackOverflow: stackoverflow.com/questions/7360473/...
James Blackburn
@JamesBlackburn: Obrigado! Muito interessante.
TJ Crowder

Respostas:

16

Eu acho que o que você está procurando é o GNU screen. Ele mantém um buffer para manter a última tela cheia ou duas da saída de um ou mais programas e permite desconectar e voltar mais tarde.

psusi
fonte
+1 para sugerir tela. BTW, você pode configurá-lo para conter muitas "linhas do histórico".
Shunz
1
Obrigado. Você pode dar um exemplo de como aplicaria isso aos comandos que mostrei na minha pergunta? A página de manual diz que é um gerenciador de janelas (acho que eles significam em um sentido terminal, não gráfico, mas ainda assim). E ainda seria capaz de entrar (via ssh) e sair conforme necessário? (Por exemplo, ops em servidores remotos.)
TJ Crowder
Sim, você pode usar a tela GNU dessa maneira. Você criaria uma nova sessão (potencialmente nomeada), executaria seu comando dentro dessa sessão e desconectaria.
TML
2
Também há tmuxe dtach- qualquer coisa na mesma classe do aplicativo multiplexador de terminal / gerenciador de sessão deve conseguir a mesma coisa.
Jw013
5

Você pode usar pv, ele fornece o buffer que você deseja em um pipeline. Você pode usá-lo assim:

sprewingprocess | pv -B 1g > ordinaryfifo &

Isso daria até 1 GB de buffer entre spewingprocesse o fifo. A maioria das distribuições Linux oferece pvem um pacote chamado, acredite ou não pv,.

David Schwartz
fonte
Obrigado, mas esse bloco não ficaria assim que o buffer estivesse cheio se eu não estivesse lendo o alvo chamado pipe?
TJ Crowder
1
Sim, mas que escolha você tem? Em um universo finito, você não pode ter buffer literalmente ilimitado.
David Schwartz
A outra opção é como descrevi na minha pergunta: Não armazenando toda a saída. Quando o buffer está cheio, o material mais antigo é jogado fora.
TJ Crowder
Hmm, eu testei isso e, infelizmente, não funciona totalmente. Se o processo de leitura do fifo parar de ler por um tempo, o pv bloqueia a tentativa de gravar no fifo e, como não é multithread, isso também bloqueia a leitura dos dados no buffer do pv. Portanto, o buffer do pv só continuará sendo preenchido enquanto o processo de leitura do fifo continuar lendo. O pv pode ler e armazenar em buffer alguns dados, mas não impede que o gravador bloqueie completamente.
Daniel S. Sterling
1

Eu tive o mesmo problema. Esta é a minha primeira solução. Primeiro, grave a saída em um arquivo que truncamos após cada linha para que não cresça indefinidamente:

spewingprocess | while read line; do echo $line > buffer.txt ; done

Em seguida, leia o arquivo usando tail (onde 2> /dev/nullse livra da mensagem de erro "arquivo truncado"):

tail -f ./buffer.txt 2> /dev/null

Dessa forma, o buffer não cresce e podemos multiplexar, por exemplo, executar quantas caudas quisermos. No entanto, o problema dessa abordagem é que podemos perder dados quando truncamos mais rapidamente do que a cauda pode ler, como mostra este teste:

for ((i=0; ; i++)) ; do echo "$i" ; done | while read line; do  echo $line > buffer.txt ; done
tail -f ./buffer.txt 2> /dev/null > log.txt

Após algum tempo de execução, a primeira e a última linha são:

$ head -n 1 log.txt
0
$ tail -n 1 log.txt
78783

Mas o arquivo tem menos linhas, então algumas são perdidas:

$ wc log.txt
67087  67087 392819 log.txt

Ainda assim, isso parece uma boa solução, se você não se importa tanto com a perda de dados ou quando o processo de spewing não é rápido o suficiente para a perda de dados.

bterwijn
fonte