Как реализовать «генераторы», такие как $ RANDOM?

Специальная переменная $RANDOM имеет новое значение при каждом обращении к ней. В этом отношении он напоминает «генераторные» объекты, найденные на некоторых языках.

Есть ли способ реализовать что-то подобное в zsh ?

Я попытался сделать это с помощью именованных каналов, но я не нашел способ извлечь элементы из fifo контролируемым образом, не убивая процесс «генератор». Например:

 % mkfifo /tmp/ints % (index=0 while ( true ) do echo $index index=$(( index + 1 )) done) > /tmp/ints & [1] 16309 % head -1 /tmp/ints 0 [1] + broken pipe ( index=0 ; while ( true; ); do; echo $index; index=$(( ... 

Есть ли другой способ реализовать такой объект типа генератора в zsh?


EDIT: Это не работает:

 #!/usr/bin/env zsh FIFO=/tmp/fifo-$$ mkfifo $FIFO INDEX=0 while true; do echo $(( ++INDEX )) > $FIFO; done & cat $FIFO 

Если я поставил вышеприведенный сценарий и запустил его, вывод редко ожидаемой отдельной строки

 1 

скорее, он обычно состоит из нескольких целых чисел; например

 1 2 3 4 5 

Количество произведенных линий варьируется от одного прогона к другому.

EDIT2: Как заметил Джимми, изменение echo в /bin/echo заботится о проблеме.

3 Solutions collect form web for “Как реализовать «генераторы», такие как $ RANDOM?”

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 

Ваш подход терпит неудачу, потому что в head -1 /tmp/ints , голова открывает 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 ) & 

Таким образом, единственная проблема заключается в том, что вы одновременно запускаете несколько кошек (все они открывают fifo, прежде чем наш цикл записи будет готов открыть его для записи), и в этом случае они будут делиться echo выходом.

Я бы также посоветовал не создавать фиксированные имена, читаемые по всему миру fifos (или любые файлы по этому поводу) в мировых каталогах, доступных для записи, например /tmp если только это не сервис для всех пользователей системы.

Если вы хотите выполнять код всякий раз, когда считывается значение переменной, вы не можете сделать это внутри самого zsh. Переменная RANDOM (как и другие аналогичные специальные переменные) жестко закодирована в исходном коде zsh. Однако вы можете определить похожие специальные переменные, написав модуль в C. Многие стандартные модули определяют специальные переменные.

Вы можете использовать сопроцессор для создания генератора.

 coproc { i=0; while echo $i; do ((++i)); done } for ((x=1; x<=3; x++)) { read -pn; echo $n; } 

Однако это довольно ограниченно, потому что у вас может быть только один сопроцесс. Еще один способ постепенного получения результата от процесса – перенаправление из подстановки процесса .

 exec 3< <(i=0; while echo $i; do ((++i)); done) for ((x=1; x<=3; x++)) { read n <&3; echo $n; } 

Обратите внимание, что head -1 здесь не работает, поскольку он считывает весь буфер, выводит то, что ему нравится, и выходит. Данные, которые были прочитаны из трубы, остаются считанными; это внутреннее свойство труб (вы не можете снова загружать данные). Встроенное read позволяет избежать этой проблемы, читая один байт за раз, что позволяет остановить его, как только он найдет первую новую строку, но очень медленный (конечно, не имеет значения, просто ли вы читаете несколько сотен байт) ,

Думаю, я сделаю это с каким-то сигналом.

 ( trap "read zero </tmp/ints" PIPE while kill -s PIPE -0 do i=$zero while echo $((i++)) do :; done 2>/dev/null >/tmp/ints done )& 

Во всяком случае, это работает для меня.


 $ echo 15 >/tmp/ints; head -n 5 </tmp/ints 15 16 17 18 19 $ echo 75 >/tmp/ints; head -n 5 </tmp/ints 75 76 77 78 79 

На единственной незначительной заметке, вот что-то странное, что я обнаружил на днях:

 mkdir nums; cd nums for n in 0 1 2 3 4 5 6 7 do ln -s ./ "$n"; done echo [0-3]/*/* 

 0/0/0 0/0/1 0/0/2 0/0/3 0/0/4 0/0/5 0/0/6 0/0/7 0/1/0 0/1/1 0/1/2 0/1/3 0/1/4 0/1/5 0/1/6 0/1/7 0/2/0 0/2/1 0/2/2 0/2/3 0/2/4 0/2/5 0/2/6 0/2/7 0/3/0 0/3/1 0/3/2 0/3/3 0/3/4 0/3/5 0/3/6 0/3/7 0/4/0 0/4/1 0/4/2 0/4/3 0/4/4 0/4/5 0/4/6 0/4/7 0/5/0 0/5/1 0/5/2 0/5/3 0/5/4 0/5/5 0/5/6 0/5/7 0/6/0 0/6/1 0/6/2 0/6/3 0/6/4 0/6/5 0/6/6 0/6/7 0/7/0 0/7/1 0/7/2 0/7/3 0/7/4 0/7/5 0/7/6 0/7/7 1/0/0 1/0/1 1/0/2 1/0/3 1/0/4 1/0/5 1/0/6 1/0/7 1/1/0 1/1/1 1/1/2 1/1/3 1/1/4 1/1/5 1/1/6 1/1/7 1/2/0 1/2/1 1/2/2 1/2/3 1/2/4 1/2/5 1/2/6 1/2/7 1/3/0 1/3/1 1/3/2 1/3/3 1/3/4 1/3/5 1/3/6 1/3/7 1/4/0 1/4/1 1/4/2 1/4/3 1/4/4 1/4/5 1/4/6 1/4/7 1/5/0 1/5/1 1/5/2 1/5/3 1/5/4 1/5/5 1/5/6 1/5/7 1/6/0 1/6/1 1/6/2 1/6/3 1/6/4 1/6/5 1/6/6 1/6/7 1/7/0 1/7/1 1/7/2 1/7/3 1/7/4 1/7/5 1/7/6 1/7/7 2/0/0 2/0/1 2/0/2 2/0/3 2/0/4 2/0/5 2/0/6 2/0/7 2/1/0 2/1/1 2/1/2 2/1/3 2/1/4 2/1/5 2/1/6 2/1/7 2/2/0 2/2/1 2/2/2 2/2/3 2/2/4 2/2/5 2/2/6 2/2/7 2/3/0 2/3/1 2/3/2 2/3/3 2/3/4 2/3/5 2/3/6 2/3/7 2/4/0 2/4/1 2/4/2 2/4/3 2/4/4 2/4/5 2/4/6 2/4/7 2/5/0 2/5/1 2/5/2 2/5/3 2/5/4 2/5/5 2/5/6 2/5/7 2/6/0 2/6/1 2/6/2 2/6/3 2/6/4 2/6/5 2/6/6 2/6/7 2/7/0 2/7/1 2/7/2 2/7/3 2/7/4 2/7/5 2/7/6 2/7/7 3/0/0 3/0/1 3/0/2 3/0/3 3/0/4 3/0/5 3/0/6 3/0/7 3/1/0 3/1/1 3/1/2 3/1/3 3/1/4 3/1/5 3/1/6 3/1/7 3/2/0 3/2/1 3/2/2 3/2/3 3/2/4 3/2/5 3/2/6 3/2/7 3/3/0 3/3/1 3/3/2 3/3/3 3/3/4 3/3/5 3/3/6 3/3/7 3/4/0 3/4/1 3/4/2 3/4/3 3/4/4 3/4/5 3/4/6 3/4/7 3/5/0 3/5/1 3/5/2 3/5/3 3/5/4 3/5/5 3/5/6 3/5/7 3/6/0 3/6/1 3/6/2 3/6/3 3/6/4 3/6/5 3/6/6 3/6/7 3/7/0 3/7/1 3/7/2 3/7/3 3/7/4 3/7/5 3/7/6 3/7/7 

Это становится более странным:

 rm * for a in abcdefgh \ ijklmnop \ qrstuvxyz do ln -s ./ "$a" done for a in * do echo "$a"/["$a"-z] done 

 a/aa/ba/ca/da/ea/fa/ga/ha/ia/ja/ka/la/ma/na/oa/pa/qa/ra/sa/ta/ua/va/xa/ya/z b/bb/cb/db/eb/fb/gb/hb/ib/jb/kb/lb/mb/nb/ob/pb/qb/rb/sb/tb/ub/vb/xb/yb/z c/cc/dc/ec/fc/gc/hc/ic/jc/kc/lc/mc/nc/oc/pc/qc/rc/sc/tc/uc/vc/xc/yc/z d/dd/ed/fd/gd/hd/id/jd/kd/ld/md/nd/od/pd/qd/rd/sd/td/ud/vd/xd/yd/z e/ee/fe/ge/he/ie/je/ke/le/me/ne/oe/pe/qe/re/se/te/ue/ve/xe/ye/z f/ff/gf/hf/if/jf/kf/lf/mf/nf/of/pf/qf/rf/sf/tf/uf/vf/xf/yf/z g/gg/hg/ig/jg/kg/lg/mg/ng/og/pg/qg/rg/sg/tg/ug/vg/xg/yg/z h/hh/ih/jh/kh/lh/mh/nh/oh/ph/qh/rh/sh/th/uh/vh/xh/yh/z i/ii/ji/ki/li/mi/ni/oi/pi/qi/ri/si/ti/ui/vi/xi/yi/z j/jj/kj/lj/mj/nj/oj/pj/qj/rj/sj/tj/uj/vj/xj/yj/z k/kk/lk/mk/nk/ok/pk/qk/rk/sk/tk/uk/vk/xk/yk/z l/ll/ml/nl/ol/pl/ql/rl/sl/tl/ul/vl/xl/yl/z m/mm/nm/om/pm/qm/rm/sm/tm/um/vm/xm/ym/z n/nn/on/pn/qn/rn/sn/tn/un/vn/xn/yn/z o/oo/po/qo/ro/so/to/uo/vo/xo/yo/z p/pp/qp/rp/sp/tp/up/vp/xp/yp/z q/qq/rq/sq/tq/uq/vq/xq/yq/z r/rr/sr/tr/ur/vr/xr/yr/z s/ss/ts/us/vs/xs/ys/z t/tt/ut/vt/xt/yt/z u/uu/vu/xu/yu/z v/vv/xv/yv/z x/xx/yx/z y/yy/z z/z Под a/aa/ba/ca/da/ea/fa/ga/ha/ia/ja/ka/la/ma/na/oa/pa/qa/ra/sa/ta/ua/va/xa/ya/z b/bb/cb/db/eb/fb/gb/hb/ib/jb/kb/lb/mb/nb/ob/pb/qb/rb/sb/tb/ub/vb/xb/yb/z c/cc/dc/ec/fc/gc/hc/ic/jc/kc/lc/mc/nc/oc/pc/qc/rc/sc/tc/uc/vc/xc/yc/z d/dd/ed/fd/gd/hd/id/jd/kd/ld/md/nd/od/pd/qd/rd/sd/td/ud/vd/xd/yd/z e/ee/fe/ge/he/ie/je/ke/le/me/ne/oe/pe/qe/re/se/te/ue/ve/xe/ye/z f/ff/gf/hf/if/jf/kf/lf/mf/nf/of/pf/qf/rf/sf/tf/uf/vf/xf/yf/z g/gg/hg/ig/jg/kg/lg/mg/ng/og/pg/qg/rg/sg/tg/ug/vg/xg/yg/z h/hh/ih/jh/kh/lh/mh/nh/oh/ph/qh/rh/sh/th/uh/vh/xh/yh/z i/ii/ji/ki/li/mi/ni/oi/pi/qi/ri/si/ti/ui/vi/xi/yi/z j/jj/kj/lj/mj/nj/oj/pj/qj/rj/sj/tj/uj/vj/xj/yj/z k/kk/lk/mk/nk/ok/pk/qk/rk/sk/tk/uk/vk/xk/yk/z l/ll/ml/nl/ol/pl/ql/rl/sl/tl/ul/vl/xl/yl/z m/mm/nm/om/pm/qm/rm/sm/tm/um/vm/xm/ym/z n/nn/on/pn/qn/rn/sn/tn/un/vn/xn/yn/z o/oo/po/qo/ro/so/to/uo/vo/xo/yo/z p/pp/qp/rp/sp/tp/up/vp/xp/yp/z q/qq/rq/sq/tq/uq/vq/xq/yq/z r/rr/sr/tr/ur/vr/xr/yr/z s/ss/ts/us/vs/xs/ys/z t/tt/ut/vt/xt/yt/z u/uu/vu/xu/yu/z v/vv/xv/yv/z x/xx/yx/z y/yy/z z/z , a/aa/ba/ca/da/ea/fa/ga/ha/ia/ja/ka/la/ma/na/oa/pa/qa/ra/sa/ta/ua/va/xa/ya/z b/bb/cb/db/eb/fb/gb/hb/ib/jb/kb/lb/mb/nb/ob/pb/qb/rb/sb/tb/ub/vb/xb/yb/z c/cc/dc/ec/fc/gc/hc/ic/jc/kc/lc/mc/nc/oc/pc/qc/rc/sc/tc/uc/vc/xc/yc/z d/dd/ed/fd/gd/hd/id/jd/kd/ld/md/nd/od/pd/qd/rd/sd/td/ud/vd/xd/yd/z e/ee/fe/ge/he/ie/je/ke/le/me/ne/oe/pe/qe/re/se/te/ue/ve/xe/ye/z f/ff/gf/hf/if/jf/kf/lf/mf/nf/of/pf/qf/rf/sf/tf/uf/vf/xf/yf/z g/gg/hg/ig/jg/kg/lg/mg/ng/og/pg/qg/rg/sg/tg/ug/vg/xg/yg/z h/hh/ih/jh/kh/lh/mh/nh/oh/ph/qh/rh/sh/th/uh/vh/xh/yh/z i/ii/ji/ki/li/mi/ni/oi/pi/qi/ri/si/ti/ui/vi/xi/yi/z j/jj/kj/lj/mj/nj/oj/pj/qj/rj/sj/tj/uj/vj/xj/yj/z k/kk/lk/mk/nk/ok/pk/qk/rk/sk/tk/uk/vk/xk/yk/z l/ll/ml/nl/ol/pl/ql/rl/sl/tl/ul/vl/xl/yl/z m/mm/nm/om/pm/qm/rm/sm/tm/um/vm/xm/ym/z n/nn/on/pn/qn/rn/sn/tn/un/vn/xn/yn/z o/oo/po/qo/ro/so/to/uo/vo/xo/yo/z p/pp/qp/rp/sp/tp/up/vp/xp/yp/z q/qq/rq/sq/tq/uq/vq/xq/yq/z r/rr/sr/tr/ur/vr/xr/yr/z s/ss/ts/us/vs/xs/ys/z t/tt/ut/vt/xt/yt/z u/uu/vu/xu/yu/z v/vv/xv/yv/z x/xx/yx/z y/yy/z z/z · a/aa/ba/ca/da/ea/fa/ga/ha/ia/ja/ka/la/ma/na/oa/pa/qa/ra/sa/ta/ua/va/xa/ya/z b/bb/cb/db/eb/fb/gb/hb/ib/jb/kb/lb/mb/nb/ob/pb/qb/rb/sb/tb/ub/vb/xb/yb/z c/cc/dc/ec/fc/gc/hc/ic/jc/kc/lc/mc/nc/oc/pc/qc/rc/sc/tc/uc/vc/xc/yc/z d/dd/ed/fd/gd/hd/id/jd/kd/ld/md/nd/od/pd/qd/rd/sd/td/ud/vd/xd/yd/z e/ee/fe/ge/he/ie/je/ke/le/me/ne/oe/pe/qe/re/se/te/ue/ve/xe/ye/z f/ff/gf/hf/if/jf/kf/lf/mf/nf/of/pf/qf/rf/sf/tf/uf/vf/xf/yf/z g/gg/hg/ig/jg/kg/lg/mg/ng/og/pg/qg/rg/sg/tg/ug/vg/xg/yg/z h/hh/ih/jh/kh/lh/mh/nh/oh/ph/qh/rh/sh/th/uh/vh/xh/yh/z i/ii/ji/ki/li/mi/ni/oi/pi/qi/ri/si/ti/ui/vi/xi/yi/z j/jj/kj/lj/mj/nj/oj/pj/qj/rj/sj/tj/uj/vj/xj/yj/z k/kk/lk/mk/nk/ok/pk/qk/rk/sk/tk/uk/vk/xk/yk/z l/ll/ml/nl/ol/pl/ql/rl/sl/tl/ul/vl/xl/yl/z m/mm/nm/om/pm/qm/rm/sm/tm/um/vm/xm/ym/z n/nn/on/pn/qn/rn/sn/tn/un/vn/xn/yn/z o/oo/po/qo/ro/so/to/uo/vo/xo/yo/z p/pp/qp/rp/sp/tp/up/vp/xp/yp/z q/qq/rq/sq/tq/uq/vq/xq/yq/z r/rr/sr/tr/ur/vr/xr/yr/z s/ss/ts/us/vs/xs/ys/z t/tt/ut/vt/xt/yt/z u/uu/vu/xu/yu/z v/vv/xv/yv/z x/xx/yx/z y/yy/z z/z - a/aa/ba/ca/da/ea/fa/ga/ha/ia/ja/ka/la/ma/na/oa/pa/qa/ra/sa/ta/ua/va/xa/ya/z b/bb/cb/db/eb/fb/gb/hb/ib/jb/kb/lb/mb/nb/ob/pb/qb/rb/sb/tb/ub/vb/xb/yb/z c/cc/dc/ec/fc/gc/hc/ic/jc/kc/lc/mc/nc/oc/pc/qc/rc/sc/tc/uc/vc/xc/yc/z d/dd/ed/fd/gd/hd/id/jd/kd/ld/md/nd/od/pd/qd/rd/sd/td/ud/vd/xd/yd/z e/ee/fe/ge/he/ie/je/ke/le/me/ne/oe/pe/qe/re/se/te/ue/ve/xe/ye/z f/ff/gf/hf/if/jf/kf/lf/mf/nf/of/pf/qf/rf/sf/tf/uf/vf/xf/yf/z g/gg/hg/ig/jg/kg/lg/mg/ng/og/pg/qg/rg/sg/tg/ug/vg/xg/yg/z h/hh/ih/jh/kh/lh/mh/nh/oh/ph/qh/rh/sh/th/uh/vh/xh/yh/z i/ii/ji/ki/li/mi/ni/oi/pi/qi/ri/si/ti/ui/vi/xi/yi/z j/jj/kj/lj/mj/nj/oj/pj/qj/rj/sj/tj/uj/vj/xj/yj/z k/kk/lk/mk/nk/ok/pk/qk/rk/sk/tk/uk/vk/xk/yk/z l/ll/ml/nl/ol/pl/ql/rl/sl/tl/ul/vl/xl/yl/z m/mm/nm/om/pm/qm/rm/sm/tm/um/vm/xm/ym/z n/nn/on/pn/qn/rn/sn/tn/un/vn/xn/yn/z o/oo/po/qo/ro/so/to/uo/vo/xo/yo/z p/pp/qp/rp/sp/tp/up/vp/xp/yp/z q/qq/rq/sq/tq/uq/vq/xq/yq/z r/rr/sr/tr/ur/vr/xr/yr/z s/ss/ts/us/vs/xs/ys/z t/tt/ut/vt/xt/yt/z u/uu/vu/xu/yu/z v/vv/xv/yv/z x/xx/yx/z y/yy/z z/z 
  • Остановить ZSH от попытки исправления команды
  • Добавление дополнительных привязок к Emacs в редактор строк ZSH (ZLE)
  • Переменная среды $ PATH, по-видимому, не распознается
  • Экран: «Невозможно выполнить exec / my / path / to / zsh» с локальной оболочкой
  • bash vs zsh: scoping и `typeset -g`
  • Как я могу получить постоянный dirstack с уникальными записями в zsh?
  • Исключение имени каталога в рекурсивном глобусе zsh
  • echo {Z..A}; out {Z..A}; Почему?
  • zsh: подстановка команды не наследует stdin из родительского
  • Папка псевдонимов исполняемых файлов с добавленным ключевым словом
  • Как я могу получить завершение работы zsh в середине имени файла?
  • Interesting Posts

    Debian apt-get install запрашивает DVD Binary

    Исключения для управления ssh ControlMaster

    Переслать многоадресную рассылку между двумя сегментами локальной сети (Chromecast)

    Каков максимальный разрешенный размер файла (и папки) с помощью eCryptfs?

    Какова полезность команды: в сценариях оболочки, учитывая, что она явно ничего не делает?

    Файлы размером более 1 ГБ и старше 6 месяцев

    Статус и зависимости службы Solaris

    Я получаю странный установочный экран на Kali Linux, и когда я устанавливаю полностью, я получаю синий экран?

    Какая способность делать что-то «на лету» и способность делать то же самое, что и в Unix / Linux?

    Как диагностировать тайм-аут соединения SSH?

    Почему карта вставки «<F4>» непредсказуемо вставляет себя или выполняет намеченные штрихи?

    Сжатие раздела Windows для установки Fedora 20

    Диапазоны массивов с пользовательским размером шага в оболочках Борна

    Автоматическое управление запуском / usr / bin / find

    Есть ли буфер обмена в системах без GUI Ubuntu / Linux? Могу ли я синхронизировать его с моим локальным (OS X) буфером обмена?

    Linux и Unix - лучшая ОС в мире.