ksh93
a des disciplines qui sont généralement utilisées pour ce genre de chose. Avec zsh
, vous pouvez détourner la fonction de répertoire nommé dynamique :
Définissez par exemple:
zsh_directory_name() {
case $1 in
(n)
case $2 in
(incr) reply=($((++incr)))
esac
esac
}
Et puis vous pouvez utiliser ~[incr]
pour obtenir une incrémentation à $incr
chaque fois:
$ echo ~[incr]
1
$ echo ~[incr] ~[incr]
2 3
Votre approche échoue car dans head -1 /tmp/ints
, head ouvre le fifo, lit un tampon complet, imprime une ligne, puis le ferme . Une fois fermée, l'extrémité d'écriture voit un tuyau cassé.
Au lieu de cela, vous pouvez soit faire:
$ 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à, nous laissons la fin de lecture ouverte sur fd 3 et read
lisons un octet à la fois, pas un tampon complet pour être sûr de lire exactement une ligne (jusqu'au caractère de nouvelle ligne).
Ou vous pourriez faire:
$ 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
Cette fois, nous instancions un tuyau pour chaque valeur. Cela permet de renvoyer des données contenant un nombre arbitraire de lignes.
Cependant, dans ce cas, dès que cat
le fifo est ouvert, la echo
boucle et est débloquée, donc plus echo
pourrait être exécutée, au moment de cat
lire le contenu et de fermer le tuyau (ce qui oblige le prochain echo
à instancier un nouveau tuyau).
Une solution de contournement pourrait être d'ajouter du retard, comme par exemple en exécutant un externe echo
comme suggéré par @jimmij ou en ajouter sleep
, mais cela ne serait toujours pas très robuste, ou vous pourriez recréer le canal nommé après chaque echo
:
while
mkfifo $fifo &&
echo $((++incr)) > $fifo &&
rm -f $fifo
do : nothing
done &
Cela laisse toujours de courtes fenêtres où le tuyau n'existe pas (entre le unlink()
fait par rm
et le mknod()
fait par mkfifo
) provoquant l' cat
échec, et des fenêtres très courtes où le tuyau a été instancié mais aucun processus n'y réécrira jamais (entre le write()
et le close()
done by echo
) cat
ne renvoyant rien, et des fenêtres courtes où le pipe nommé existe toujours mais rien ne l'ouvrira jamais pour écrire (entre le close()
done by echo
et le unlink()
done by rm
) où cat
va se bloquer.
Vous pouvez supprimer certaines de ces fenêtres en procédant comme suit:
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 cette façon, le seul problème est que si vous exécutez plusieurs chats en même temps (ils ouvrent tous le fifo avant que notre boucle d'écriture soit prête à l'ouvrir pour l'écriture), auquel cas ils partageront la echo
sortie.
Je déconseille également la création de noms fixes, de fifos lisibles par tout le monde (ou de tout fichier important) dans des répertoires accessibles en écriture, à /tmp
moins que ce soit un service à exposer à tous les utilisateurs du système.