Linux

當管道連接到 grep -q -m1 時,Cygwin 2.9.0 cat/tac 命令在大文件上失敗

  • January 21, 2019

我在 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: write error: No space left on device”。

請注意,只有當至少一個 { -m1, -q} 選項被傳遞給grep命令時才會發生這種情況,匹配在文件的第一個處理行附近(因為cat它靠近開頭,因為tac它靠近結尾),並且文件很大。

我執行了該df命令,它報告 Cygwin 驅動器上有 14 MB 可用空間,實際磁碟上有 60 GiB 可用空間。我知道我可以簡單地將 STDERR 重定向到 NUL 設備,但這似乎是一個 hacky 解決方法。有誰知道如何正確解決這個問題?

開始編輯

我從 2017 年 5 月發現了另一份關於相同錯誤的報告,但沒有提出解決方案。另一篇文章的 OP 確實表明他認為這是管道緩衝區大小限制(可能在 Windows 上,可能在 Cygwin 中)。

我發現了一些解決方法。只需更改命令:

tac &lt;file&gt; | grep -q -m1 -F "literal string"

到以下之一:

bash -c "tac &lt;file&gt; | grep -q -m1 -F 'literal string'"
stdbuf -o L tac &lt;file&gt; | grep -q -m1 -F "literal string"

我認為第一個有效是因為它使用的是 Linux 管道,第二個是因為它強制tac命令輸出被行緩衝。這兩種形式都會使錯誤消失。

由於這可行,我猜問題是grep一旦找到第一個匹配項就停止處理輸入緩衝區,但tac繼續處理輸入。一旦緩衝區已滿(可能是 64kiB),緩衝區就會阻塞並tac退出,並出現指定的錯誤。但是,由於tac在崩潰之前成功處理了我關心的線路,所以一切都按預期工作。

對這些選項進行計時表明呼叫 tobash是更快的選項。這可能是因為使用 Linux 管道,一旦找到第一個匹配項tac就能夠立即返回。grep

引用自:https://serverfault.com/questions/949985