我在 Windows 10 Pro x64 上使用 Cygwin x64 2.9.0 时发现一些奇怪的行为。我尝试运行的命令如下:
tac <file> | grep -q -m1 -F "literal string"
上述命令对我向其发送的所有小文件(小文件指 <= 15kB)均成功执行。如果 的最后一次出现位置literal string
靠近文件开头(例如,literal string
出现在文件顶部附近,而不在其他地方),则该命令也会成功执行。最后,当未将 { -q
、-m1
} 标志传递给grep
命令时,该命令也会成功执行。
但是,当文件大小约为 680kB 时,如果literal string
出现在文件末尾附近,则tac
命令会将“tac: write error”打印到 STDERR。尽管出现此错误,但命令似乎已成功,将匹配的行打印到输出(省略标志时-q
)并从 获得适当的返回值grep
。
进一步的测试表明,使用时也会出现同样的错误cat
,只不过literal string
必须出现在文件开头附近才会产生错误,而产生的错误是“cat:写入错误:设备上没有剩余空间”。
请注意,仅当至少将 { -m1
, -q
} 选项之一传递给grep
命令、匹配项靠近文件的第一个处理行(因为cat
它靠近开头,因为tac
它靠近结尾)并且文件很大时,才会发生这种情况。
我运行了该df
命令,它报告 Cygwin 驱动器上有 14 MB 可用空间,实际磁盘上有 60 GiB 可用空间。我知道我可以简单地将 STDERR 重定向到 NUL 设备,但这似乎是一种不靠谱的解决方法。有人知道如何正确修复这个问题吗?
开始编辑
我发现另一份报告2017 年 5 月出现了同样的错误,但没有提出解决方案。另一篇帖子的 OP 确实表示他认为这是管道缓冲区大小限制(可能在 Windows 上,也可能在 Cygwin 中)。
答案1
我发现了一些解决方法。只需更改命令:
tac <file> | grep -q -m1 -F "literal string"
至以下之一:
bash -c "tac <file> | grep -q -m1 -F 'literal string'"
stdbuf -o L tac <file> | grep -q -m1 -F "literal string"
我认为第一种方式有效是因为它使用了 Linux 管道,第二种方式是因为它强制tac
命令输出为行缓冲。这两种方式都可以消除错误。
由于这有效,我猜问题是grep
一旦找到第一个匹配项,它就会停止处理输入缓冲区,但tac
会继续处理输入。一旦缓冲区已满(可能是 64kiB),缓冲区就会阻塞并tac
退出并出现指定的错误。但是,由于tac
在崩溃之前成功处理了我关心的行,所以一切都按预期运行。
对这些选项进行计时表明调用bash
是更快的选项。这可能是因为使用 Linux 管道,一旦找到第一个匹配项,tac
就能够立即返回。grep