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.
command echo
ou/bin/echo
au lieu de intégréecho
. De plus - vous pouvez faire cette commande un peu plus courte:repeat 999 /bin/echo $((++incr)) > /tmp/int &
.Si vous souhaitez exécuter du code chaque fois que la valeur d'une variable est lue, vous ne pouvez pas le faire à l'intérieur de zsh lui-même. La
RANDOM
variable (comme d'autres variables spéciales similaires) est codée en dur dans le code source zsh. Vous pouvez cependant définir des variables spéciales similaires en écrivant un module en C. De nombreux modules standard définissent des variables spéciales.Vous pouvez utiliser un coprocessus pour créer un générateur.
Cependant, cela est assez limité car vous ne pouvez avoir qu'un seul coprocessus. Une autre façon d'obtenir progressivement la sortie d'un processus consiste à rediriger à partir d'une substitution de processus .
Notez que
head -1
cela ne fonctionne pas ici, car il lit un tampon entier, affiche ce qu'il aime et quitte. Les données qui ont été lues dans le canal restent lues; il s'agit d'une propriété intrinsèque des canaux (vous ne pouvez pas replacer les données). Leread
builtin évite ce problème en lisant un octet à la fois, ce qui lui permet de s'arrêter dès qu'il trouve la première nouvelle ligne, mais est très lent (bien sûr, cela n'a pas d'importance si vous ne lisez que quelques centaines d'octets).la source
bash
, voir la section bash sur ce lien.coproc
coprocesses, je veux dire, pas vides)coproc cmd1; exec 3>&p 4<&p; coproc cmd2 3>&- 4<&-...
Je pense que je le ferais avec un signal quelconque.
Cela fonctionne pour moi, de toute façon.
Sur une note seulement légèrement liée, voici quelque chose de bizarre que j'ai découvert l'autre jour:
Cela devient de plus en plus étrange:
la source
bash
le comportement a changé? Je pense que la déclaration depwd
ne pas vérifier et de ne se référer qu'à$PWD
est incorrecte.mkdir /tmp/dir; cd $_; PS4='$OLDPWD, $PWD + '; set -x; OLDPWD=$OLDPWD PWD=$PWD command eval ' cd ..; cd ..; cd ~; pwd'; pwd; cd .; pwd
pourrait vous montrer ce que je veux dire. C'est un problème qui m'a mis sur écoute avec cettens()
chose.