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
если это не служба, доступная для всех пользователей в системе.
command echo
или/bin/echo
вместо встроенногоecho
. Кроме того - вы можете сделать эту команду немного короче:repeat 999 /bin/echo $((++incr)) > /tmp/int &
.Если вы хотите выполнять код всякий раз, когда читается значение переменной, вы не можете сделать это внутри самого zsh.
RANDOM
Переменной (как и другие подобные специальные переменные) жестко закодировано в исходном коде ЗШ. Однако вы можете определить аналогичные специальные переменные, написав модуль на C. Многие стандартные модули определяют специальные переменные.Вы можете использовать сопроцесс для создания генератора.
Однако это довольно ограничено, потому что вы можете иметь только один сопроцесс. Другим способом постепенного получения выходных данных процесса является перенаправление из подстановки процесса .
Обратите внимание, что
head -1
это не работает, потому что он читает весь буфер, печатает то, что ему нравится, и выходит. Данные, которые были прочитаны из канала, остаются прочитанными; это внутреннее свойство каналов (вы не можете вставить данные обратно).read
Встроенная избегает этого вопроса, прочитав один байт в то время, что позволяет ему остановиться , как только он находит первый символ новой строки , но очень медленно (конечно , что не имеет значения , если вы просто читаете несколько сотен байт).источник
bash
, см. раздел bash по этой ссылке.coproc
сопроцессы, я имею в виду, а не зпты)coproc cmd1; exec 3>&p 4<&p; coproc cmd2 3>&- 4<&-...
Я думаю, что я сделал бы это с сигналом некоторого вида.
Во всяком случае, у меня это работает.
На только немного связанной ноте вот что странное я обнаружил на днях:
Это становится еще более странным:
источник
bash
, поведение изменилось? Я считаю неверным утверждение о том, чтоpwd
не нужно проверять и ссылаться только на$PWD
.mkdir /tmp/dir; cd $_; PS4='$OLDPWD, $PWD + '; set -x; OLDPWD=$OLDPWD PWD=$PWD command eval ' cd ..; cd ..; cd ~; pwd'; pwd; cd .; pwd
может показать вам, что я имею в виду Это проблема, которая беспокоила меня с этойns()
вещью.