我正在 Ubuntu 中尝试命名管道,并且之前没有使用它们的经验。我做了以下事情:
mkfifo pipe
ls>pipe&
cat pipe
这将输入我的文件夹中所有文件的列表pipe
并显示它们。我正在尝试一次读取管道 2 行。因此,我想要一个命令在执行一次时给出文件夹中第一个和第二个文件的名称。如果再次执行该命令,我需要第三个和第四个文件名。有什么办法可以做到吗?
我试过head -2 pipe
。它显示前两个文件名。但再次执行时,却挂了。正确的前进方向是什么?
答案1
您希望在读取端保持 fifo 打开。一种方法是让 bash 保留一个打开的文件描述符。
#!/bin/bash
mkfifo pipe
ls > pipe &
exec 8< pipe
r2(){
read -ru 8 fn1
read -ru 8 fn2
echo "$fn1" "$fn2"
}
r2 # print out first 2 files
sleep 1 # do something
r2 # print out next 2 files.
答案2
您需要一个读取两行且不超过两行的命令。
当输入不是管道时能够做到这一点可寻找的,命令有三种选择:
- 一次读取一个字节,直到找到第二个换行符。
- 查看(不消耗)管道的内容以查看第二个换行符的位置,然后一次性读取尽可能多的数据。
- 读取块中的输入,但如果他们发现读取的内容超过了两行,则将读取过多的内容放回管道中。
1 在许多系统上都很昂贵,因为read()
每个字节只有一个系统调用。 2 和 3 并不适用于所有系统,因为并非所有系统都支持查看管道或将数据放回管道,并且当多个进程同时从管道读取数据时,这也是不可靠的。
所以一般来说,除了少数例外,命令一般不会费心去读确切地当他们的输入不可搜索时,他们被告知多少行。
对于 的大多数实现head
,head -n2
将输出其输入的前两行,但可能会消耗更多输入。一个值得注意的例外是head
ksh93 shell 的内置函数,如果可以的话,它会进行查看,否则一次读取一个字节。
可以告诉一些命令以确保它们不会读取超过它们被告知要处理的最后一行的内容。
对于 GNU sed
,可以选择-u
:
sed -u 2q
将读取 2 行(一次 1 个字节),仅此而已。
该line
实用程序(不再是标准实用程序,因此现在并不总是可以找到)是一种只读取一行的实用程序。
要求内置read
的sh
不能读取超过一行。因此line
上面的命令可以通过以下方式实现:
IFS= read -r line; printf '%s\n' "$line"
(需要注意的是,即使输入行没有终止,它也会添加换行符)。
(POSIX 实际上证明删除是合理的,line
因为它可以通过 来实现read
)。
对于line
不添加额外换行符并在 eof 上返回 false 的实现。
line() {
if IFS= read -r line; then
printf '%s\n' "$line"
else
printf %s "$line"
false
fi
}
并且twolines
只是:
twolines() { line && line; }
然后你可以这样做:
mkfifo pipe
ls > pipe &
while
echo next two lines:
twolines
do
continue
done < pipe