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
если это не служба, доступная для всех пользователей в системе.