ksh93tiene disciplinas que generalmente se usan para este tipo de cosas. Con zsh, podría secuestrar la función de directorio dinámico con nombre :
Definir por ejemplo:
zsh_directory_name() {
case $1 in
(n)
case $2 in
(incr) reply=($((++incr)))
esac
esac
}
Y luego puede usar ~[incr]para obtener un incremento $incrcada vez:
$ echo ~[incr]
1
$ echo ~[incr] ~[incr]
2 3
Su enfoque falla porque en head -1 /tmp/ints, head abre el fifo, lee un búfer completo, imprime una línea y luego la cierra . Una vez cerrado, el final de la escritura ve una tubería rota.
En cambio, podrías hacer lo siguiente:
$ 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
Allí, dejamos abierto el final de lectura en fd 3 y readlee un byte a la vez, no un búfer completo para asegurarnos de leer exactamente una línea (hasta el carácter de nueva línea).
O podrías hacer:
$ 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
Esa vez, instanciamos una tubería para cada valor. Eso permite devolver datos que contienen cualquier número arbitrario de líneas.
Sin embargo, en ese caso, tan pronto como se catabre el fifo, echose desbloquea el bucle y, por lo que echopodría ejecutarse más, para cuando catlea el contenido y cierre la tubería (haciendo que la próxima echoinstancia una nueva tubería).
Una echosolución podría ser agregar algún retraso, como por ejemplo ejecutando un externo como lo sugiere @jimmij o agregar algunos sleep, pero eso aún no sería muy robusto, o podría recrear la tubería con nombre después de cada uno echo:
while
mkfifo $fifo &&
echo $((++incr)) > $fifo &&
rm -f $fifo
do : nothing
done &
Eso todavía deja ventanas cortas donde la tubería no existe (entre el unlink()hecho por rmy el mknod()hecho por mkfifo) haciendo catque falle, y ventanas muy cortas donde la tubería ha sido instanciada pero ningún proceso volverá a escribirle (entre el write()y el close()hecho por echo) haciendo catque no se devuelva nada, y las ventanas cortas donde todavía existe la tubería nombrada pero nada la abrirá para escribir (entre close()hecho por echoy unlink()hecho por rm) donde catse bloqueará.
Puede eliminar algunas de esas ventanas haciéndolo como:
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
) &
De esa manera, el único problema es si ejecuta varios cat al mismo tiempo (todos abren el fifo antes de que nuestro bucle de escritura esté listo para abrirlo para escribir) en cuyo caso compartirán la echosalida.
También recomendaría no crear nombres fijos, juegos legibles en todo el mundo (o cualquier archivo que importe) en directorios de escritura mundial, a /tmpmenos que sea un servicio que se exponga a todos los usuarios del sistema.