ksh93
ma dyscypliny, które są zwykle używane do tego rodzaju rzeczy. Dzięki zsh
, można porwać katalogu dynamiczny o nazwie funkcji :
Zdefiniuj na przykład:
zsh_directory_name() {
case $1 in
(n)
case $2 in
(incr) reply=($((++incr)))
esac
esac
}
A następnie możesz użyć, ~[incr]
aby uzyskać przyrost za $incr
każdym razem:
$ echo ~[incr]
1
$ echo ~[incr] ~[incr]
2 3
Twoje podejście kończy się niepowodzeniem, ponieważ w head -1 /tmp/ints
, głowa otwiera fifo, czyta pełny bufor, drukuje jedną linię, a następnie ją zamyka . Po zamknięciu koniec pisania widzi zepsutą rurkę.
Zamiast tego możesz albo:
$ 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
Tam zostawiamy otwarty koniec odczytu na fd 3 i read
odczytujemy jeden bajt na raz, a nie pełny bufor, aby upewnić się, że przeczytano dokładnie jedną linię (do znaku nowej linii).
Lub możesz zrobić:
$ 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
Tym razem tworzymy instancję potoku dla każdej wartości. Umożliwia to zwracanie danych zawierających dowolną liczbę wierszy.
Jednak w takim przypadku, gdy tylko cat
otwiera się fifo, echo
pętla i jest odblokowywana, aby echo
można było uruchomić więcej, zanim cat
odczyta zawartość i zamknie potok (powodując, że następny echo
utworzy nowy potok).
Rozwiązaniem może być dodanie opóźnienia, na przykład poprzez uruchomienie zewnętrznego, echo
jak sugeruje @jimmij, lub dodanie go sleep
, ale nadal nie byłoby to zbyt solidne, lub można odtworzyć nazwaną potok po każdym echo
:
while
mkfifo $fifo &&
echo $((++incr)) > $fifo &&
rm -f $fifo
do : nothing
done &
Że nadal pozostawia krótkie okna gdzie nie istnieją rura (między unlink()
zrobione przez rm
i mknod()
wykonywane przez mkfifo
) spowodowanie cat
, by upaść, i bardzo krótkich okna gdzie rura została instancja ale nie proces będzie kiedykolwiek ponownie napisać do niego (między write()
i close()
zrobione przez echo
) powodując, cat
że nic nie zwróci, i krótkie okna, w których nazwany potok nadal istnieje, ale nic nigdy go nie otworzy do zapisu (między close()
wykonanym przez echo
a unlink()
wykonanym przez rm
) gdzie cat
zawiesi się.
Możesz usunąć niektóre z tych okien , wykonując następujące czynności:
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
) &
W ten sposób jedynym problemem jest uruchomienie kilku kotów jednocześnie (wszystkie otwierają fifo, zanim nasza pętla zapisu będzie gotowa do otwarcia go do zapisu), w którym to przypadku będą dzielić dane echo
wyjściowe.
Odradzałbym także tworzenie stałych nazw, czytelnych na całym świecie fifos (lub jakichkolwiek innych plików w tym zakresie) w katalogach zapisywalnych na świecie, takich jak /tmp
chyba, że jest to usługa dostępna dla wszystkich użytkowników w systemie.