$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=$(( ...
Run Code Online (Sandbox Code Playgroud)
有没有其他方法可以在 zsh 中实现这种生成器类型的对象?
编辑:这不起作用:
#!/usr/bin/env zsh
FIFO=/tmp/fifo-$$
mkfifo $FIFO
INDEX=0
while true; do echo $(( ++INDEX )) > $FIFO; done &
cat $FIFO
Run Code Online (Sandbox Code Playgroud)
如果我将上述内容放在脚本中并运行它,则输出很少是预期的单行
1
Run Code Online (Sandbox Code Playgroud)
相反,它通常由几个整数组成;例如
1
2
3
4
5
Run Code Online (Sandbox Code Playgroud)
产生的线数从一次运行到下一次运行不同。
EDIT2:正如 jimmij 所指出的,更改echo
为/bin/echo
可以解决问题。
Sté*_*las 11
ksh93
有通常用于这种事情的学科。使用zsh
,您可以劫持动态命名目录功能:
定义例如:
zsh_directory_name() {
case $1 in
(n)
case $2 in
(incr) reply=($((++incr)))
esac
esac
}
Run Code Online (Sandbox Code Playgroud)
然后你可以使用每次~[incr]
增加$incr
:
$ echo ~[incr]
1
$ echo ~[incr] ~[incr]
2 3
Run Code Online (Sandbox Code Playgroud)
您的方法失败,因为 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
Run Code Online (Sandbox Code Playgroud)
在那里,我们让读取端在 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
Run Code Online (Sandbox Code Playgroud)
那个时候,我们为每个值实例化一个管道。这允许返回包含任意行数的数据。
但是,在这种情况下,一旦cat
打开 fifo,echo
循环就会被解除阻塞,因此echo
在cat
读取内容并关闭管道(导致 nextecho
实例化新管道)时可以运行更多。
解决方法可能是添加一些延迟,例如通过运行echo
@jimmij 建议的外部或添加 some sleep
,但这仍然不是很健壮,或者您可以在每个 之后重新创建命名管道echo
:
while
mkfifo $fifo &&
echo $((++incr)) > $fifo &&
rm -f $fifo
do : nothing
done &
Run Code Online (Sandbox Code Playgroud)
这仍然会留下管道不存在的短窗口(在unlink()
done byrm
和mknod()
done by 之间mkfifo
)导致cat
失败,以及非常短的窗口,其中管道已被实例化但没有进程将再次写入它(在write()
和close()
done by echo
) 导致cat
不返回任何内容,以及命名管道仍然存在的短窗口,但没有任何内容将其打开以进行写入(在close()
done byecho
和unlink()
done by 之间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
) &
Run Code Online (Sandbox Code Playgroud)
这样,唯一的问题是如果您同时运行多个 cat(它们都在我们的写入循环准备打开它以进行写入之前打开 fifo)在这种情况下它们将共享echo
输出。
我还建议不要在世界可写目录中创建固定名称、世界可读的 fifos(或任何与此相关的文件),/tmp
除非它是向系统上的所有用户公开的服务。
归档时间: |
|
查看次数: |
861 次 |
最近记录: |