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.
command echo
o en/bin/echo
lugar de integradoecho
. También - usted puede hacer este comando un poco más corto:repeat 999 /bin/echo $((++incr)) > /tmp/int &
.Si desea ejecutar código cada vez que se lee el valor de una variable, no puede hacerlo dentro de zsh. La
RANDOM
variable (como otras variables especiales similares) está codificada en el código fuente zsh. Sin embargo, puede definir variables especiales similares escribiendo un módulo en C. Muchos de los módulos estándar definen variables especiales.Puedes usar un coproceso para hacer un generador.
Sin embargo, esto es bastante limitado porque solo puede tener un coproceso. Otra forma de obtener progresivamente la salida de un proceso es redirigir desde una sustitución de proceso .
Tenga en cuenta que
head -1
no funciona aquí, porque lee un búfer completo, imprime lo que le gusta y sale. Los datos que se han leído de la tubería siguen siendo leídos; Esta es una propiedad intrínseca de las tuberías (no se pueden volver a introducir datos). Elread
builtin evita este problema al leer un byte a la vez, lo que le permite detenerse tan pronto como encuentra la primera línea nueva pero es muy lento (por supuesto, eso no importa si solo está leyendo unos pocos cientos de bytes).fuente
bash
, consulte la sección bash en ese enlace.coproc
coprocesos, quiero decir, no zpty)coproc cmd1; exec 3>&p 4<&p; coproc cmd2 3>&- 4<&-...
Creo que lo haría con una señal de algún tipo.
Funciona para mí de todos modos.
En una nota ligeramente relacionada, aquí hay algo extraño que descubrí el otro día:
También se vuelve más extraño:
fuente
bash
el comportamiento ha cambiado? Creo que la afirmación sobrepwd
no verificar y referirse solo$PWD
es incorrecta.mkdir /tmp/dir; cd $_; PS4='$OLDPWD, $PWD + '; set -x; OLDPWD=$OLDPWD PWD=$PWD command eval ' cd ..; cd ..; cd ~; pwd'; pwd; cd .; pwd
podría mostrarte lo que quiero decir. Es un problema que me molestó con estons()
.