The man
page for grep
describes the -d ACTION
option as follows:
If an input file is a directory, use
ACTION
to process it. By default,ACTION
isread
, i.e., read directories just as if they were ordinary files. [...]
Intuitively, I would expect this to mean that a directory bar
is treated (for grep
ping purposes) as the equivalent of a text file containing something more or less along the lines of what vim
displays if I type vim foo
, i.e., something roughly (up to variation is what sort of explanatory information and/or metadata is at the top and bottom) like:
"============================================================================
" 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
If this were the case, then grep -H foo bar
would produce the output
bar: foobar/
Instead, it gives the message grep: bar: Is a directory
. Why is this? And is there any (reasonably straightforward) way to get the intuitive result (not just on this simple search, but also for searches like grep foo *
where *
may match any or all of text files, binary files, and directories)?
ETA (2021-07-22): As suggested by the accepted answer and confirmed in the comments, grep foo bar
itself actually does exactly what I'd expect it to do: It invokes the system call read
(ssize_t read(int fd, void *buf, size_t count)
) with the file descriptor for bar
, just as it would if bar
were an ordinary file. And when read
, instead of filling *buf
with the contents of bar
, returns the error code EISDIR
, grep
prints an appropriate diagnostic message, then continues on to the next file - just as it would if read
returned an error code (other than EINTR
or, sometimes, EINVAL
) and bar
were an ordinary file.
The difference between my expectation and reality comes from the behavior of the Linux version (and, judging by comments, most other modern versions) of read
, namely that when fd
refers to a directory, it automatically returns EISDIR
.
ETA2 (2021-07-23): The primary motivation for this question was not a pressing need to get the intuitive behavior described (although I was interested in that as a potential secondary benefit). The motivation was to understand why (GNU) grep
seemed, based on its output, to be behaving in a manner that contradicted a statement in its man page.
The answer turned out to be that grep
was actually doing just what its man page said it would, but that changes to the (typical) behavior of the system call read
make the result of that, on most modern systems, substantially different from what one would infer based solely on a reading of the grep
man page (without being familiar with the behavior of modern read
implementations.
While it's true that I would rather, on the whole, that read
didn't behave like that, I rather doubt that that behavior contradicts its man page. Given the current situation, I would like to see a line or two added to the grep
man page, but it's not wrong as it is, just misleading.