14

I am following the best answer on How do I find all files containing specific text on Linux? to search string in my project.

This is my command grep --include=*.rb -rnw . -e "pattern"

Zsh tells me that zsh: no matches found: --include=*.rb

It seems that grep doesn't support --include option.

When I type grep --help, it returns

usage: grep [-abcDEFGHhIiJLlmnOoPqRSsUVvwxZ] [-A num] [-B num] [-C[num]]
    [-e pattern] [-f file] [--binary-files=value] [--color=when]
    [--context[=num]] [--directories=action] [--label] [--line-buffered]
    [--null] [pattern] [file ...]

no --include here.

Is my grep version too old? Or is there something wrong with my command?

Community
  • 1
  • 1
icemelon
  • 1,651
  • 2
  • 18
  • 25

2 Answers2

26

FreeBSD/macOS grep does support the --include option (see man grep; it's unfortunate that the command-line help (grep -h) doesn't list this option), but your problem is that the option argument, *.rb, is unquoted.

As a result, it is your shell, zsh, that attempts to pathname-expand --include=*.rb up front, and fails, because the current directory contains no files with names matching glob pattern *.rb.
grep never even gets to execute.

Since your intent is to pass *.rb unmodified to grep, you must quote it:

grep --include='*.rb' -rnw . -e "pattern"     

To include multiple globs:

  • Pass an --include option for each; e.g.:

    grep --include='*.rb' --include=='*.h*' -rnw . -e "pattern"     
    
  • Alternatively, in shells that support brace expansion - notably bash, ksh, and zsh - you can let your shell create these multiple options for you, as follows - note the selective quoting (see this answer for a detailed explanation):

    grep '--include=*.'{rb,'h*'} -rnw . -e "pattern"     
    
mklement0
  • 382,024
  • 64
  • 607
  • 775
  • Still can't fix the pattern `grep 'pattern' -rIn '--include=*.{c*,h*}'`` – linzuojian Oct 10 '21 at 23:22
  • 1
    @linzuojian, you're trying to use _brace expansion_, which (a) only _some_ shells support and (b) only if used _unquoted_. `grep` itself does _not_ understand this notation. Please see my update, which shows how to use brace expansion properly, and links to an answer with background information. – mklement0 Oct 11 '21 at 01:45
3

If your grep does not support --include, and you don't want to install GNU grep just for this, there are a number of portable ways to perform the same operation. Off the top of my head, try

find . -type f -name '*.rb' -exec grep -nw "pattern" /dev/null {} \;

The find command traverses the directory (like grep -r) looking for files named *.rb (like the --include option) and the /dev/null is useful because grep shows a slightly different output format when you run it on multiple files.

This is slightly inefficient because it runs a separate grep for each file. If it's too slow, look into xargs (or use find -exec ... {} \+ instead of ... {} \; if your find supports that). This is a very common task; you should easily find thousands of examples.

You might also want to consider ack which is a popular and somewhat more user-friendly alternative. It is self-contained, so "installation" amounts to copying it to your $HOME/bin.

mklement0
  • 382,024
  • 64
  • 607
  • 775
tripleee
  • 175,061
  • 34
  • 275
  • 318
  • No: FreeBSD _also_ supports `--include`; it's just not listed in the _command-line_ help (but is in `man grep`); the OP's issue is the use of _unquoted_ glob `*.rb`. To avoid the inefficiency of multiple `grep` invocations, simply use `+` instead of `\;`, which gives you `xargs`-like behavior: `find . -type f -name '*.rb' -exec grep -nw "pattern" {} +`. Thanks for the `ack` tip - hadn't heard of it. – mklement0 Jun 13 '14 at 05:25
  • Thanks for your update. I was unsure of what's supported on `osx` and what `zsh` brings into the picture. Added `find ... -exec ... \+` to the answer; thanks for pointing that out. – tripleee Jun 13 '14 at 05:35
  • My pleasure; you say regarding the `+` feature: `if your find supports that`; actually, it is part of POSIX - see http://man.cx/find. Would you mind modifying your introduction to no longer suggest that _only_ GNU `grep` supports `--include`? – mklement0 Jun 13 '14 at 06:11
  • Standard or not, I have boxes where GNU `find` is so old as to not support `-exec ... \+` (GNU find 4.1.20, Debian 3.1 [sic]) – tripleee Jun 13 '14 at 06:55
  • Interesting, thanks for letting me know. (A tiny aside: the `\ ` in `\;` is solely needed to protect `;` from interpretation by the _shell_ (as a command separator) - The `\ ` gets "eaten" by the shell and `find` only sees `;`. Since `+` is not special to the shell, it needn't be escaped that way (though it doesn't do any harm either), so `-exec ... {} +` will do. However, I can see that someone might choose to still use it for symmetry and not having to remember special cases.) – mklement0 Jun 13 '14 at 15:58