當管道連接到 grep -q -m1 時,Cygwin 2.9.0 cat/tac 命令在大文件上失敗
我在 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 <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
在崩潰之前成功處理了我關心的線路,所以一切都按預期工作。對這些選項進行計時表明呼叫 to
bash
是更快的選項。這可能是因為使用 Linux 管道,一旦找到第一個匹配項tac
就能夠立即返回。grep