Как реализовать «генераторы», такие как $ 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 печатает полную строку с printf '% .s'?
  • Как настроить zsh для запуска меню - для параметров команды?
  • Запустите zsh с помощью специального zshrc
  • Как можно настроить псевдонимы bash для обработки пробелов в именах каталогов?
  • Физический терминал (DEC VT220) с ZSH
  • Проблема в активации среды на сервере UAT
  • Zsh очистить командную строку от вызова zsh / sched
  • Различные оболочки для интерактивной и неинтерактивной работы
  • Абсолютный путь к текущему zsh?
  • Как объединить zw autocomplete для аргументов функции-оболочки и существующей команды
  • Почему urxvtc не активирует функции zsh при вызове с аргументом «-c»?
  • Interesting Posts

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

    Xterm не загружает цветовые схемы

    перенаправить вывод оболочки в файл, даже когда я убиваю программу

    Найти файлы, содержащие строку, и не содержать другой

    Удалить определенные номера строк (переданные как переменные) из файла в linux

    Fedora 20 не принимает правильный PIN-код для мобильного широкополосного доступа

    Как я могу добавить пакет к установке Ubuntu по умолчанию?

    SOCKS5 существует шифрование между клиентом и прокси-сервером?

    Как передать аргумент скрипту, который вводится в bash

    Подавление автоматической загрузки модулей ядра Linux

    смена каталога происходит очень медленно

    Почему tar не хватает места на диске, когда его осталось?

    Тупик при чтении / ожидании

    печать данных на основе строк в формате таблицы в Linux

    Что значит быть в группе 0?

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