The man page for grep describes the -d ACTION option as follows:
If an input file is a directory, use
ACTIONto process it. By default,ACTIONisread, 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 grepping 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.
readdir()by synthesizing the data in some standard format and having it available withread(). Apparently not FreeBSD though. – ilkkachu Jul 20 '21 at 20:32readdiron top ofreadis traditional, but these days I think the unices that still allowreadon directories are more likely to provide it as a backward compatibility hack withreaddone as a system call that synthesizes something inside the kernel (or maybe as a library function on top ofgetdentsor the like, but that would be less backward compatible since it wouldn't work for statically linked programs). – Gilles 'SO- stop being evil' Jul 20 '21 at 21:09reading directories just as if they were ordinary files, butreadis returning an error (specifically, EISDIR), which grep is then printing a textual representation of, just as it would ifreadreturned an error on an ordinary file," yes? – Chris Henry Jul 22 '21 at 00:50readsystem call, the system call returnsEISDIR, and grep prints the name of the file that it couldn't read and the string associated to theEISDIRerror in yourLC_MESSAGESlocale. – Gilles 'SO- stop being evil' Jul 22 '21 at 09:52