ksh93a 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 à $incrchaque 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 readlisons 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 catle fifo est ouvert, la echoboucle et est débloquée, donc plus echopourrait être exécutée, au moment de catlire 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 echocomme 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 rmet 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) catne 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 echoet le unlink()done by rm) où catva 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 echosortie.
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, à /tmpmoins que ce soit un service à exposer à tous les utilisateurs du système.