ksh93
tem 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 $incr
cada 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 read
lê 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 cat
abre o fifo, o echo
loop é desbloqueado, para que mais echo
possa ser executado, quando cat
o conteúdo é lido e fechado o pipe (fazendo com que o próximo echo
instancie um novo pipe).
Uma echo
soluçã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 rm
e o mknod()
done by mkfifo
) causando cat
falhas, 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 cat
com 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 echo
e o unlink()
done by rm
) em que cat
irá 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 echo
saí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 /tmp
menos que seja um serviço a ser exposto a todos os usuários no sistema.