0

The day to day usage is:

grep -rIn pattern directory

There are some files that I want to avoid, they are in directories that have this kind of path in them at some point: app/lib/bower/lodash, app/lib/bower/paho-mqtt-js, app/lib/bower/socket-io-client.

Ideal solution is to detect app/lib/bower/ in the path, but it's hard. Is it possible?

I've come up with:

alias grep='grep --exclude-dir={lodash,paho-mqtt-js,socket-io-client}'

Good enough (though needs maintenance when new stuff is added). How to at least add a short warning into stderr if the directory is excluded by grep?

1
  • Why not just use alias exgrep='grep --exclude-dir={lodash,paho-mqtt-js,socket-io-client}', so if you use exgrep, you know there is something excluded? Apr 28 at 12:09

1 Answer 1

0

I'd use find:

mygrep() (
  pattern=$1; shift
  find "$@" -type d -path '*/app/lib/bower' -exec sh -c '
    printf >&2 "Warning: ignoring \"%s\" directory\n" "$@"
    ' sh {} + -prune -o -type f -exec grep -IHne "$pattern" {} +
)

(-I and -H being GNU extensions).

Use as:

mygrep pattern dir1 dir2

(making sure dir1 and dir2 don't look like find predicates).

Remove the -exec sh...+ if you don't care about those warning messages.

It's a bad idea to use grep as your alias name when you change its behaviour so dramatically.

If you need to pass options to grep, you could use the GREP_OPTIONS variable like:

GREP_OPTIONS=-i mygrep foo dir

But note that support for that option will be removed in future versions of grep, so a better option might be to give a way in mygrep to pass options to grep like with a dedicated array if your shell supports them:

mygrep() (
  pattern=$1; shift
  find "$@" -type d -path '*/app/lib/bower' -exec sh -c '
    printf >&2 "Warning: ignoring \"%s\" directory\n" "$@"
    ' sh {} + -prune -o -type f -exec \
    grep -IHne "${g[@]}" "$pattern" {} +
)

g=(-i --exclude-dir=.git); mygrep foo dir1 dir2

Or use -- to tell mygrep where the options stop:

mygrep() (
  grep_options=()
  for i do
    grep_options+=("$i")
    shift
    [ "$i" != "--" ] || break
  done
  pattern=${1?need a pattern}; shift
  find "$@" -type d -path '*/app/lib/bower' -exec sh -c '
    printf >&2 "Warning: ignoring \"%s\" directory\n" "$@"
    ' sh {} + -prune -o -type f -exec \
    grep -H "${grep_options[@]}" "$pattern" {} +
)

mygrep -nI --exclude-dir=.git -- pattern dir1 dir2

(and make sure you don't pass -- as an option arguments, as in if you want to exclude the -- files, use --exclude=--, not --exclude -- for instance. That also precludes usages like mygrep -e pattern1 -e pattern2 -- dir or mygrep -f patternfile -- dir).

2
  • That's a different syntax.
    – Velkan
    Sep 29, 2016 at 9:18
  • @Velkan if you mean that g=(-i --exclude-dir=.git); mygrep foo dir1 dir2 is a different syntax from grep -i --exclude-dir=.git -rIn foo dir1 dir2, then yes but for mygrep to be able to understand that syntax, we'd need it to know which of those arguments are the pattern and the directories and for that we'd need it to implement the full option parser of your grep implementation which would not be practical. Sep 29, 2016 at 9:46

You must log in to answer this question.

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