Chr*_*nry 0 grep directory read
该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
Run Code Online (Sandbox Code Playgroud)
如果是这种情况,那么grep -H foo bar
将产生输出
bar: foobar/
Run Code Online (Sandbox Code Playgroud)
相反,它给出了信息grep: bar: Is a directory
。为什么是这样?是否有任何(相当简单的)方法来获得直观的结果(不仅在这个简单的搜索中,而且在搜索诸如grep foo *
where*
可能匹配任何或所有文本文件、二进制文件和目录)?
ETA (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
or,有时,EINVAL
)并且bar
是一个普通文件。
我的期望与现实之间的差异来自 Linux 版本(以及根据评论判断,大多数其他现代版本)的行为read
,即当fd
引用目录时,它会自动返回EISDIR
.
ETA2 (2021-07-23):这个问题的主要动机不是迫切需要获得所描述的直觉行为(尽管我对此感兴趣,因为它是潜在的次要好处)。动机是为了理解为什么 (GNU)grep
根据其输出,其行为方式与其手册页中的声明相矛盾。
答案原来是它grep
实际上只是按照其手册页所说的那样做,但是系统调用的(典型)行为的变化read
使得在大多数现代系统上的结果与人们推断的结果大不相同仅基于对grep
手册页的阅读(不熟悉现代read
实现的行为。
虽然总体上read
我更愿意那样做,但我很怀疑这种行为与其手册页相矛盾。鉴于目前的情况,我希望在grep
手册页中添加一两行,但这并没有错,只是误导。
目录没有作为文本的内在表示。许多 Unix 变体允许程序从目录中读取,就好像它是一个普通文件,但这通常是无用的,因为内容的格式取决于文件系统。一些现代 Unix 变体,包括 Linux,完全阻止程序读取目录,就好像它是一个普通文件。
例如,下面是 FreeBSD 上发生的事情(旧版本仍然允许它 - 从 FreeBSD 13 开始,默认情况下这是禁用的),目录如下bar
:
$ grep -H foo bar
Binary file bar matches
$ grep -H --text foo bar
bar:?"!
.?
..?"!foobar?"!
baz?"!qux
Run Code Online (Sandbox Code Playgroud)
是的,您可以确定它foo
存在于目录表示中,但您不能确定它是文件名的一部分。例如(仍然在那台 FreeBSD 机器上):
$ rmdir bar/foobar
$ grep -H --text foo bar
bar:?"!
..?"!foobar?"!
baz?"!foo
Run Code Online (Sandbox Code Playgroud)
删除目录将其从文件系统中删除,但它并没有从对目录进行编码的磁盘结构中擦除已删除条目的名称。
当您要求 Vim 打开一个目录时,Vim 会遍历该目录(使用专用的系统函数,例如readdir
,而不是使用通用read
函数)并以一种很好的方式显示结果。
Grep 可以实现类似的东西,但是相对于 grep 的大小,这将是很多工作,它会偏离 grep 的核心目的,即搜索文件的内容,并且实现必须是一种折衷方案,不会满足不了很多人。目录作为文本的表示是否只包含文件名或一些元数据(为什么没有grep "Jul 20" bar
找到在 7 月 20 日修改的文件)?如何分隔条目(如果它们由换行符分隔,则表示形式不明确,因为文件名可以包含换行符;如果它们由空字节分隔,则输出仅对 有用grep --null-data
)?
要搜索文件名,已经有更好的工具,例如 shell 通配符find
和locate
.