Quando você faz:
cat fifo
Supondo que nenhum outro processo tenha aberto o fifo
para gravação ainda, cat
bloqueará a chamada do sistema open()
. Quando outro processo abrir o arquivo para gravação, um canal será instanciado e open()
retornará. cat
chamará read()
em um loop e read()
bloqueará até que algum outro processo grave dados no pipe.
cat
verá o final do arquivo (eof) quando todos os outros processos de escrita tiverem fechado seu descritor de arquivo para o fifo
. Em que pontos cat
termina e o tubo é destruído¹.
Você precisaria executar cat
novamente para ler o que será gravado depois disso no fifo
(mas por meio de uma instância de pipe diferente).
Em:
tail -f file
Como cat
, tail
aguardará um processo para abrir um arquivo para gravação. Mas aqui, como você não especificou -n +1
para copiar desde o início, tail
precisará aguardar até eof para descobrir quais foram as últimas 10 linhas, para que você não veja nada até que o fim da escrita seja fechado.
Depois disso, tail
não irá fechar seu fd para o pipe, o que significa que a instância do pipe não será destruída, e ainda tentará ler o pipe a cada segundo (no Linux, essa pesquisa pode ser evitada via uso de inotify
e algumas versões do GNU tail
fazem isso lá. Esse read()
retornará com eof (imediatamente, e é por isso que você vê 100% da CPU com -s 0
(que com GNU tail
significa não esperar entre read()
s em vez de esperar por um segundo)) até que outro processo abre o arquivo novamente para gravação.
Aqui, em vez disso, você pode querer usar cat
, mas certifique-se de que a instância do pipe permaneça sempre após ser instanciada. Para isso, na maioria dos sistemas, você poderia fazer:
cat 0<> fifo # the 0 is needed for recent versions of ksh93 where the
# default fd changed from 0 to 1 for the <> operator
O stdin de cat
estará aberto para leitura e escrita, o que significa que cat
nunca verá eof sobre ele (também instancia o pipe imediatamente mesmo se não houver outro processo abrindo fifo
para escrita) .
Em sistemas onde isso não funciona, você pode fazer isso:
cat < fifo 3> fifo
Dessa forma, assim que algum outro processo abrir o fifo
para gravação, o primeiro percentual somente de leituraopen()
retornará, ponto no qual o shell fará o% somente gravaçãoopen()
antes de iniciar cat
, o que impedirá que o cano seja novamente destruído.
Então, para resumir:
- comparado a
cat file
, não pararia após a primeira rodada. - comparado a
tail -n +1 -f file
: ele não usariaread()
inútil a cada segundo após a primeira rodada, nunca haveria eof na única instância da tubulação, não haveria esse atraso de até um segundo quando segundo processo abre o pipe para escrever depois que o primeiro fechou. - comparado a
tail -f file
. Além do acima, ele não teria que esperar que a primeira rodada terminasse antes de produzir algo (apenas as últimas 10 linhas). - comparado a
cat file
em um loop, haveria apenas uma instância de pipe. As janelas de corrida mencionadas em ¹ seriam evitadas.
¹ neste ponto, entre o último read()
que indica eof e cat
terminando e fechando o final de leitura do pipe, há realmente uma pequena janela durante a qual um processo poderia abrir o fifo
para gravação novamente (e não ser bloqueado, pois ainda há um final de leitura). Então, se ele escrever algo depois que cat
tenha saído e antes que outro processo abra o fifo
para leitura, ele será morto com um SIGPIPE.