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?

5
  • 5
  • 3
    You don't really want to prevent the shell from passing these files, do you? The question is rather how to tell grep that they aren't options.
    – DonHolgo
    May 17, 2019 at 11:57
  • 11
    ...to be clear, bash doesn't control which results are treated as options vs treated as arguments; that's in the receiving program's control. You'd get the same behavior with, say, subprocess.Popen(['grep', '-r', '-e' 'stuff', '--corporate-discount.csv']) in Python, no bash anywhere. May 17, 2019 at 15:37
  • 2
    Related reading: Unix Wildcards Gone Wild, about security issues that can be caused by using * in commands. ALL of these can be avoided by using ./* instead.
    – Wildcard
    May 17, 2019 at 19:57
  • 2
    @Wildcard, using -- as an end-of-options sigil is perfectly reasonable as well; POSIX utility syntax guidelines require it to be honored; see guideline #10. (Sure, not all programs follow POSIX guidelines, but the answer is to string up the offending programs' authors and/or eject them from the industry). May 18, 2019 at 17:27

2 Answers 2

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.

0
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" *
7
  • 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
    – user232326
    May 18, 2019 at 15:20
  • Yes, a grep -r -- stuff * is simpler, and works with non-GNUish greps also. So: added, thanks. @StéphaneChazelas
    – user232326
    May 18, 2019 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 May 19, 2019 at 3: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. May 19, 2019 at 6:16
  • 1
    See also echo [!-]* as a standard equivalent of ksh's (or bash -O extglob's) echo !(-*). May 19, 2019 at 8:32

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .