ksh93
tiene 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 $incr
cada 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 read
lee 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 cat
abre el fifo, echo
se desbloquea el bucle y, por lo que echo
podría ejecutarse más, para cuando cat
lea el contenido y cierre la tubería (haciendo que la próxima echo
instancia una nueva tubería).
Una echo
solució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 rm
y el mknod()
hecho por mkfifo
) haciendo cat
que 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 cat
que 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 echo
y unlink()
hecho por rm
) donde cat
se 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 echo
salida.
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 /tmp
menos que sea un servicio que se exponga a todos los usuarios del sistema.