ksh93имеет дисциплины, которые обычно используются для такого рода вещей. С помощью zshвы можете захватить функцию динамического именованного каталога :
Определите, например:
zsh_directory_name() {
case $1 in
(n)
case $2 in
(incr) reply=($((++incr)))
esac
esac
}
И тогда вы можете использовать, ~[incr]чтобы получить приращение $incrкаждый раз:
$ echo ~[incr]
1
$ echo ~[incr] ~[incr]
2 3
Ваш подход терпит неудачу, потому что in head -1 /tmp/ints, head открывает fifo, читает полный буфер, печатает одну строку, а затем закрывает ее . После закрытия пишущий конец видит сломанную трубу.
Вместо этого вы можете сделать:
$ 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
Там мы оставляем конец чтения открытым на fd 3 и readчитаем по одному байту за раз, а не полный буфер, чтобы быть уверенным, что читаем ровно одну строку (до символа новой строки).
Или вы могли бы сделать:
$ 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
На этот раз мы создаем канал для каждого значения. Это позволяет возвращать данные, содержащие произвольное количество строк.
Тем не менее, в этом случае, как только catоткроется fifo, echoцикл «и» разблокируется, так что больше времени echoможно будет запустить к тому времени, catкогда содержимое прочитает и закроет канал (что приведет к следующему echoсозданию нового канала).
echoОбходной путь может заключаться в добавлении некоторой задержки, например, путем запуска внешнего, как предложено @jimmij, или добавления некоторых sleep, но это все равно не будет очень надежным, или вы можете воссоздать именованный канал после каждого echo:
while
mkfifo $fifo &&
echo $((++incr)) > $fifo &&
rm -f $fifo
do : nothing
done &
Это по-прежнему оставляет короткие окна, в которых канал не существует (между unlink()выполненным rmи mknod()выполненным mkfifo), что приводит catк сбою, и очень короткие окна, в которых был создан экземпляр канала, но ни один процесс больше никогда не запишет в него (между write()и close()выполнено путем echo) catничего не возвращая, и короткие окна, где именованный канал все еще существует, но ничто никогда не откроет его для записи (между close()выполненным echoи unlink()выполненным rm), где catбудет висеть.
Вы можете удалить некоторые из этих окон , сделав это следующим образом:
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
) &
Таким образом, единственная проблема заключается в том, что вы запускаете несколько cat одновременно (все они открывают fifo до того, как наш цикл записи готов открыть его для записи), и в этом случае они будут делиться echoвыводом.
Я также не рекомендовал бы создавать фиксированные имена, читаемые во всем мире данные (или любой другой файл в этом отношении) в таких каталогах, которые доступны для записи, например, /tmpесли это не служба, доступная для всех пользователей в системе.