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*
可能匹配任何或所有文本文件、二进制文件和目录之类的搜索)?
预计到达时间 (2021-07-22):正如已接受的答案所建议的并在评论中确认的那样,grep foo bar
它本身实际上完全符合我的预期:它使用文件描述符 for调用系统调用read
( ) ,就像普通文件一样。当 时,不是填充的内容,而是返回错误代码,打印适当的诊断消息,然后继续处理下一个文件 - 就像返回错误代码(有时不是 或)并且是普通文件。ssize_t read(int fd, void *buf, size_t count)
bar
bar
read
*buf
bar
EISDIR
grep
read
EINTR
EINVAL
bar
我的期望和现实之间的差异来自于 Linux 版本(以及从评论来看,大多数其他现代版本)的行为read
,即当fd
引用目录时,它会自动返回EISDIR
。
预计到达时间2 (2021-07-23):这个问题的主要动机并不是迫切需要获得所描述的直观行为(尽管我对此作为潜在的次要好处感兴趣)。动机是理解为什么(GNU)grep
根据其输出,其行为方式似乎与其手册页中的声明相矛盾。
答案是,grep
实际上正在按照其手册页所述进行操作,但是对系统调用的(典型)行为的更改read
使得结果其中,在大多数现代系统上,这与仅根据阅读手册grep
页(不熟悉现代read
实现的行为)所推断的内容有很大不同。
虽然总的来说,我确实宁愿read
不这样做,但我相当怀疑这种行为是否与它是手册页。鉴于目前的情况,我希望看到在grep
手册页中添加一两行,但事实并非如此错误的事实上,只是误导。
答案1
目录没有文本形式的内在表示。许多 Unix 变体允许程序像读取常规文件一样从目录中读取数据,但这几乎没有用,因为内容的格式取决于文件系统。一些现代 Unix 变体,包括 Linux,完全阻止程序读取目录,就好像它是常规文件一样。
例如,下面是 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
.