I am trying to add recursive support to my filegrep script.

For some reason this does not work as expected:


# iterate over args
for ARG in "$@"
    if [ -d "$ARG" ] && [ $RECURSIVE_MODE = on ] ; then
        # recursive call
        $0 $GREP_ARGS $ARG/*
    elif [ -f "$ARG" ]; then
        filecat "$ARG" | grep $GREP_ARGS | sed "s#^#$ARG: #"
        [ "$ARG" = "-r" ] && RECURSIVE_MODE=on
        # append to the current grep args

I'd like to avoid using functions in this case for better readability.

EDIT: the script should work like this:

for each passed arg:

  • if the current arg is a directory, check if recursive mode is enabled and if yes do the recursive call;
  • else if the current arg is a file, call grep with the current pattern;
  • else assume the current arg is a grep pattern or a grep switch and append it to the current $GREP_ARGS list.

Maybe this is not completely reliable, but it works fine for me as a replacement for zgrep, pdfgrep, etc.

  • Instead of writing a script like this, you would be better off learning how regexps work (hint: to grep for multiple alternate patterns, use | in extended regexps or \| in basic RE), as well as the available command-line options of grep (e.g. -r for recursing a directory). For example: e.g. grep -E -r 'pattern1|pattern2|pattern3|...|patternN' /path/to/directory/. Also worth noting is that grep already knows how to deal with multiple file or dir arguments. Your wrapper script is entirely superfluous - it doesn't do anything that grep doesn't already do. Read man grep. – cas May 21 '16 at 5:52
  • This has nothing to do with combining multiple patterns. Also grep cannot parse binary files natively (that's why there are wrappers like zgrep, pdfgrep, etc.). – eadmaster May 22 '16 at 5:30
  • What does the # append to the query pattern comment mean, then? zgrep may not understand grep's -r option, but that's what find ... -exec is for. BTW, pdfgrep isn't a wrapper around grep, it's a stand-alone program. My point, however, was that by not bothering to learn to use existing tools, you are making things much more difficult for yourself than they need to be and, worse, re-inventing those tools poorly. – cas May 22 '16 at 6:06
  • I've added a description of the code to (hopefully) make more clear how it works. I've also renamed $PATTERN to GREP_ARGS to avoid confusion. – eadmaster May 22 '16 at 6:56

Try using the -H option to grep:

   -H, --with-filename
          Print the filename for each match.

So instead of calling your script, just do:

grep -H PATTERN [FILE...]

Also, it's a good idea to check the man page for the tool you are using before you attempt writing a wrapper script. For common Unix tool, the simple options you want are nearly always built into the tool already.

  • the purpose of the script is not just adding the filename: prefix. It is made as a companion to filecat, to grep in any filetype (something that regular grep cannot do) – eadmaster May 21 '16 at 3:19
  • @eadmaster, that's terrible. You're using filenames to tell you the type of file. That's unreliable and a bad idea. Why not just use file, or better yet, just use zgrep directly? Again, read the manuals because you don't need to reinvent the wheel. (And if you do, at least make it round.) – Wildcard May 21 '16 at 4:43
  • ‘zgrep‘ only supports some archive types and it is a crappy wrapper just like mine. ’filegrep’ supports many different filetypes instead. I agree the filenames are not 100% reliable , btw in some cases ‘file’ is not helpful too (e.g. with odt files). – eadmaster May 21 '16 at 11:07
  • @eadmaster, file *.odt on my box returns OpenDocument Text quite reliably on my system—how is that not helpful? – Wildcard May 21 '16 at 11:25
  • 1
    @eadmaster, when you reach the point where you are trying to implement recursion in a shell script, you need to review your architectural decisions. More bluntly and assertively: There is no real-life use case where the best real-life answer is a recursive shell script. Best of luck to you, though. – Wildcard May 22 '16 at 7:40

I've finally found the problem was that grep with the -r switch ignores stdin and search in the current working directory instead. To force stdin reading, i've just added a -:

filecat "$ARG" | grep $GREP_ARGS - | sed "s#^#$ARG: #"

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.