14

I'm trying to recursively search a string with grep but I get this:

$ grep -r "stuff" *
grep: unrecognized option '---corporate-discount.csv'
Usage: grep [OPTION]... PATTERN [FILE]...
Try 'grep --help' for more information.

How can I prevent Bash from passing files starting with - as argument?

terdon
  • 242,166
Chef Tony
  • 455

2 Answers2

43

First, note that the interpretation of arguments starting with dashes is up to the program being started, grep or other. The shell has no direct way to control it.

Assuming you want to process such files (and not ignore them completely), grep, along with most programs, recognizes -- as indicating the end of options, so

grep -r -e "stuff" -- *

will do what you want. The -e is there in case stuff starts with a - as well.

Alternatively, you can also use:

grep -r -e "stuff"  ./*

That latter one would also avoid the problem if there was a file called - in the current directory. Even after the -- separator, grep interprets - as meaning stdin, while ./- is the file called - in the current directory.

ilkkachu
  • 138,973
icarus
  • 17,920
8

To prevent Bash expansion from passing files starting with “-” you can use:

echo [!-]*

Which works portably in most shells, or, specific to ksh, bash, zsh:

echo !(-*)

For example: in a directory with this files

$ echo *
a b c ---corporate-discount.csv d -e --option.txt

Will list only (provided extglob is active):

$ shopt -s extglob
$ echo !(-*)
a b c d

$ echo [!-]*
a b c d

But if what you want is to process all files while telling grep to avoid interpreting files stated with a - as options, then just add a ./:

grep -r "stuff" ./*

Or, if there is guarantee that no file called exactly - exists in the files listed (grep will interpret a lonely - as read from stdin), you can use:

grep -r -- "stuff" *
  • Yes, as the question is about bash, a GNU shell, it seems reasonable to assume that a GNU grep is available, could be installed, or is actually being used. @StéphaneChazelas –  May 18 '19 at 15:20
  • Yes, a grep -r -- stuff * is simpler, and works with non-GNUish greps also. So: added, thanks. @StéphaneChazelas –  May 18 '19 at 15:27
  • @Isaac I wouldn't say it's a reasonable assumption "if bash is available, GNU grep is also available". Take for instance FreeBSD: bash isn't installed by default , which can be installed later, but there's no effect on grep - it remains BSD version of grep unless GNU grep is explicitly installed. But that's a minor nitpick. I like the alternative approach via extglob, hence +1'ed the answer – Sergiy Kolodyazhnyy May 19 '19 at 03:18
  • 2
    @SergiyKolodyazhnyy, AFAIK, grep on FreeBSD is still based on GNU grep and still has that misfeature whereby options are recognised after non-options. Even BSDs like OpenBSD that have rewritten their grep made them GNU compatible for backward portability (and still show that behaviour here). On macOS, sh is bash, but I'd expect their grep not to show that behaviour as macOS is meant to be POSIX compliant even without $POSIXLY_CORRECT. In any case, the OP's grep is GNU-compatible since it gives that error. – Stéphane Chazelas May 19 '19 at 06:16
  • @StéphaneChazelas In other words, truly POSIX-compliant grep shouldn't have problems with dash-leading filenames ? – Sergiy Kolodyazhnyy May 19 '19 at 08:15
  • @SergiyKolodyazhnyy, yes grep foo --help is required by POSIX to match foo against the lines of the --help file. GNU grep only does it when $POSIXLY_CORRECT is in the environment. You still need the -- even with POSIX compliant implementations with grep -e foo -- --help as here foo is an argument to the -e option, it's not a non-option argument. – Stéphane Chazelas May 19 '19 at 08:27
  • 1
    See also echo [!-]* as a standard equivalent of ksh's (or bash -O extglob's) echo !(-*). – Stéphane Chazelas May 19 '19 at 08:32