$RANDOMのような「ジェネレータ」を実装する方法は?

$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でこれらのジェネレータ型オブジェクトを実装する他の方法はありますか?


編集:これはうまくいきません:

#!/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:jimmijが指摘したようにに変更するとecho効果/bin/echoがあります。

ベストアンサー1

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/intsfifoを開き、バッファ全体を読み、1行を印刷し、それから閉じる。一度閉じると、書き込み側に壊れたパイプが表示されます。

代わりに、次のようにすることができます。

$ 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バッファを読み込むのではなく、一度に1バイトずつ読みます(改行文字まで)。

またはこれを行うこともできます:

$ 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

この時点で、各値のパイプをインスタンス化します。これにより、任意の数の行を含むデータを返すことができます。

ただし、この場合、catfifoが開かれるとechoループがブロック解除されるため、echo内容を読み取り、パイプが閉じられている間により多くのタスクを実行できます(新しいパイプの次のインスタンス化につながります)。catecho

回避策は、echo@jimmijが提案したように、外部の実行やいくつかの追加などのいくつかの遅延を追加することですが、sleepまだ強力ではないか、各項目の後に名前付きパイプを再作成できますecho

while 
  mkfifo $fifo &&
  echo $((++incr)) > $fifo &&
  rm -f $fifo
do : nothing
done &

これにより、パイプが存在しない短いウィンドウ(unlink()完成者rmmknod()完成者の間mkfifo)が依然としてcat失敗を引き起こし、パイプがインスタンス化されたがプロセスが書き戻されない非常に短いウィンドウが残ります(完成者と完成者のwrite()close())完成者)は何もありません返さechocatず、名前付きパイプがまだ存在するが書き込み用に何も開かない短いウィンドウ(close()完了者echounlink()完成者の間rmcatが中断されます。

その一部を削除できますWindowsこれにより:

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を開く準備ができる前にすべてfifoを開きます)。この場合、出力を共有しますecho

/tmpまた、システム内のすべてのユーザーに公開されているサービスでない限り、誰でも書き込むことができるディレクトリに、固定名の誰でも読むことができるfifo(またはその問題のすべてのファイル)を作成しないことをお勧めします。

おすすめ記事