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()
by by rm
和mknod()
done by之间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
除非它是一项要公开给系统上所有用户的服务。