為什麼“grep foo bar”列印“grep: bar: Is a directory”而不是列印 bar/ 中與模式“foo”匹配的任何文件名?
該
man
頁面grep
描述了該-d ACTION
選項,如下所示:如果輸入文件是一個目錄,使用
ACTION
它來處理它。預設情況下,ACTION
isread
,即像讀取普通文件一樣讀取目錄。$$ … $$
直覺地說,我希望這意味著一個目錄
bar
被視為(出於grep
ping 目的)相當於一個文本文件,其中包含的內容或多或少與vim
我鍵入時顯示的內容一致vim foo
,即大致的內容(取決於變化是什麼解釋性資訊和/或元數據位於頂部和底部),例如:"============================================================================ " Netrw Directory Listing (netrw v156) " /home/chris-henry/bar " Sorted by name " Sort sequence: [\/]$,\<core\%(\.\d\+\)\=\>,\.h$,\.c$,\.cpp$,\~\=\*$,*,\.o$,\.obj$,\.info$,\.swp$,\.bak$,\~$ " Quick Help: <F1>:help -:go up dir D:delete R:rename s:sort-by x:special " ============================================================================== ../ ./ foobar/ baz/ qux
如果是這種情況,那麼
grep -H foo bar
將產生輸出bar: foobar/
相反,它給出了消息
grep: bar: Is a directory
。為什麼是這樣?是否有任何(相當直接的)方法來獲得直覺的結果(不僅在這個簡單的搜尋中,而且對於像grep foo *
where*
可能匹配任何或所有文本文件、二進製文件和目錄這樣的搜尋)?**ETA (2021-07-22):**正如接受的答案所建議並在評論中確認的那樣,
grep foo bar
它本身實際上完全符合我的預期:它使用文件描述符呼叫系統呼叫read
( ) ,就像它一樣如果是一個普通的文件。而當,而不是填充的內容,返回錯誤程式碼,列印適當的診斷消息,然後繼續到下一個文件 - 就像它返回錯誤程式碼(除了或,有時,)並且是普通文件。ssize_t read(int fd, void *buf, size_t count)``bar``bar``read``*buf``bar``EISDIR``grep``read``EINTR``EINVAL``bar
我的期望和現實之間的
read
差異fd
來自EISDIR
.**ETA2 (2021-07-23):**這個問題的主要動機並不是迫切需要獲得所描述的直覺行為(儘管我對此感興趣,因為它是潛在的次要好處)。其動機是了解為什麼(GNU)
grep
根據其輸出似乎表現出與其手冊頁中的陳述相矛盾的方式。事實證明,這
grep
實際上是在按照其手冊頁所說的那樣做,但是對系統呼叫的(典型)行為的更改read
使得在大多數現代系統上,結果與人們推斷的結果大不相同僅基於閱讀grep
手冊頁(不熟悉現代read
實現的行為。雖然我確實寧願總體上
read
不那樣做,但我寧願懷疑這種行為與其手冊頁相矛盾。鑑於目前的情況,我希望在grep
手冊頁中添加一兩行,但這並沒有錯,只是誤導。
目錄沒有作為文本的內在表示。許多 Unix 變體允許程序從目錄中讀取,就好像它是一個普通文件一樣,但這幾乎沒有用,因為內容的格式取決於文件系統。包括 Linux 在內的一些現代 Unix 變體完全阻止程序像普通文件一樣讀取目錄。
例如,在 FreeBSD(仍然允許它的舊版本 - 自 FreeBSD 13 起,預設情況下禁用此功能)上發生的情況如下
bar
:$ grep -H foo bar Binary file bar matches $ grep -H --text foo bar bar:�"! .� ..�"!foobar�"! baz�"!qux
是的,您可以確定它
foo
存在於目錄表示中,但您不能確定它是文件名的一部分。例如(仍然在那台 FreeBSD 機器上):$ rmdir bar/foobar $ grep -H --text foo bar bar:�"! ..�"!foobar�"! baz�"!foo
刪除該目錄會將其從文件系統中刪除,但它不會從編碼該目錄的磁碟結構中擦除已刪除條目的名稱。
當您要求 Vim 打開一個目錄時,Vim 會遍歷該目錄(使用專用的系統函式,如
readdir
,而不是使用通用read
函式)並以一種很好的方式顯示結果。grep 可以實現類似的東西,但是相對於 grep 的大小來說,這將是很多工作,它會偏離 grep 的核心目的,即搜尋文件的內容,並且實現必須是一種妥協,不不能滿足很多人。目錄的文本表示是否僅包括文件名或一些元數據(為什麼
grep "Jul 20" bar
找不到在 7 月 20 日修改的文件)?如何分隔條目(如果它們由換行符分隔,則表示不明確,因為文件名可以包含換行符;如果它們由空字節分隔,則輸出僅對 有用grep --null-data
)?要在文件名中搜尋,已經有更好的工具,例如 shell 萬用字元
find
和locate
.