ksh93tem disciplinas que normalmente são usadas para esse tipo de coisa. Com zsh, você pode seqüestrar o recurso de diretório dinâmico nomeado :
Defina, por exemplo:
zsh_directory_name() {
case $1 in
(n)
case $2 in
(incr) reply=($((++incr)))
esac
esac
}
E então você pode usar ~[incr]para obter um incremento a $incrcada vez:
$ echo ~[incr]
1
$ echo ~[incr] ~[incr]
2 3
Sua abordagem falha porque head -1 /tmp/ints, head abre o fifo, lê um buffer completo, imprime uma linha e depois a fecha . Uma vez fechado, o final da escrita vê um cano quebrado.
Em vez disso, você pode:
$ fifo=~/.generators/incr
$ (umask 077 && mkdir -p $fifo:h && rm -f $fifo && mkfifo $fifo)
$ seq infinity > $fifo &
$ exec 3< $fifo
$ IFS= read -rneu3
1
$ IFS= read -rneu3
2
Lá, deixamos o final da leitura aberto no fd 3 e readlê um byte de cada vez, não um buffer completo, para ter certeza de ler exatamente uma linha (até o caractere de nova linha).
Ou você pode fazer:
$ fifo=~/.generators/incr
$ (umask 077 && mkdir -p $fifo:h && rm -f $fifo && mkfifo $fifo)
$ while true; do echo $((++incr)) > $fifo; done &
$ cat $fifo
1
$ cat $fifo
2
Nesse momento, instanciamos um canal para cada valor. Isso permite retornar dados contendo qualquer número arbitrário de linhas.
No entanto, nesse caso, assim que catabre o fifo, o echoloop é desbloqueado, para que mais echopossa ser executado, quando cato conteúdo é lido e fechado o pipe (fazendo com que o próximo echoinstancie um novo pipe).
Uma echosolução alternativa seria adicionar algum atraso, como por exemplo executando um externo como sugerido por @jimmij ou adicionar alguns sleep, mas isso ainda não seria muito robusto, ou você poderia recriar o canal nomeado após cada um echo:
while
mkfifo $fifo &&
echo $((++incr)) > $fifo &&
rm -f $fifo
do : nothing
done &
Isso ainda deixa janelas curtas onde o canal não existe (entre o unlink()done by rme o mknod()done by mkfifo) causando catfalhas, e janelas muito curtas onde o pipe foi instanciado, mas nenhum processo será gravado novamente nele (entre o write()e o close()done by echo) fazendo catcom que não retorne nada e janelas curtas onde o pipe nomeado ainda existe, mas nada será aberto para gravação (entre o close()done by echoe o unlink()done by rm) em que catirá travar.
Você pode remover algumas dessas janelas fazendo o seguinte:
fifo=~/.generators/incr
(
umask 077
mkdir -p $fifo:h && rm -f $fifo && mkfifo $fifo &&
while
mkfifo $fifo.new &&
{
mv $fifo.new $fifo &&
echo $((++incr))
} > $fifo
do : nothing
done
) &
Dessa forma, o único problema é se você executar vários cat ao mesmo tempo (todos eles abrem o fifo antes que o nosso loop de gravação esteja pronto para abri-lo para gravação); nesse caso, eles compartilharão a echosaída.
Eu também desaconselharia a criação de nomes fixos, fifos legíveis pelo mundo (ou qualquer arquivo para isso) em diretórios graváveis do mundo, a /tmpmenos que seja um serviço a ser exposto a todos os usuários no sistema.