不,那里没有。

不,那里没有。

我正在执行一个带有标准输入重定向的程序:

 $ prog < f

在这种情况下,标准输入将被完全缓冲。

有没有办法让它成为无缓冲或行缓冲?

编辑。

无需修改程序源码(即使用setvbuf())

答案1

不缓冲通常对于输出更有意义。输出缓冲是指应用程序在写入之前保留其输出,直到其累积到足够的量,从而最大限度地减少 I/O 数量。

在输入时,应用程序所能做的就是调整一次从输入中读取的字节数(好吧,至少是它请求的字节数,因为它不能保证收到尽可能多的字节数;文件当时可能有更少的可用字节,例如对于管道或 tty 设备)。

使用stdio,取消缓冲输入流,将该缓冲区的大小设置为一个字节。

一次读取一个字节的效率很低,而且通常不需要这样做。

可能需要它的情况是从不可查找的输入(如管道,因此f如果它是常规文件则不是您的)读取并且prog需要在文件中的给定点停止读取,以便另一个进程可以恢复读取在那时候。

例如,在:

seq 10 | { grep -q 5; cat; }

如果你想cat输出第 6 到 10 行,那就是在 wheregrep停止读取文件之后的行(这里是一个管道,所以不可查找)。

上面的命令没有返回任何内容,因为已经一口气grep读取了所有的输出。seq

请注意,如果您写的是:

{ seq 5; sleep 1; seq 6 10; } | { grep -q 5; cat; }

那会起作用的。grep也请求一个大的缓冲区,但由于当时只有前 5 行可用,所以grep处理它们并在第 5 行退出。换句话说,它不会累积其输入,直到缓冲区已满(或达到 eof)以开始处理它(我知道执行类似操作的唯一命令是mawk)。

通过某些命令,在 GNU 和 FreeBSD 系统上,您可以使用 调整输入缓冲stdbuf -i。使用stdbuf -i0(取消缓冲)与(读入大小为 1 的缓冲区)相同stdbuf -i1,并且会导致输入一次读取一个字节。

它不适用于 GNU grep,但可以与 GNU 一起使用sed

$ seq 10 | { sed -n /5/q; cat; }
$ seq 10 | { stdbuf -i0 sed -n /5/q; cat; }
6
7
8
9
10

使用strace,您可以看到 s 的大小read()正在调整:

$ seq 5 | { strace -e read sed -n /2/q; cat; }
[...]
read(0, "1\n2\n3\n4\n5\n", 4096)        = 10
+++ exited with 0 +++
$ seq 5 | { strace -e read stdbuf -i0 sed -n /2/q; cat; }
[...]
read(0, "1", 1)                         = 1
read(0, "\n", 1)                        = 1
read(0, "2", 1)                         = 1
read(0, "\n", 1)                        = 1
+++ exited with 0 +++
3
4
5
$ seq 5 | { strace -e read stdbuf -i1 sed -n /2/q; cat; }
[...]
read(0, "1", 1)                         = 1
read(0, "\n", 1)                        = 1
read(0, "2", 1)                         = 1
read(0, "\n", 1)                        = 1
+++ exited with 0 +++
3
4
5

答案2

不,那里没有。

您对问题的修改明确排除了这样做的方法。人们可以编辑程序来完成我们想要程序做的事情,或者使用一种工具来挂钩动态加载器和 C 运行时库的内部,以安排setvbuf在程序启动时进行调用。

如果setvbuf不允许使用该功能,则根本没有办法做到这一点。打电话setvbuf是一个人需要做的事情。

进一步阅读

相关内容