Skip to main content
1 of 4

Shortcut script for elusive grep command

This is an example of my filesystem:

  • /code/
    • internal/
      • dev/
      • main/
    • public/
      • dev/
      • main/
      • release/
    • tools/

/code/internal/dev/, /code/public/dev/ and /code/tools/ contain subdirectories for multiple projects. I work almost exclusively in the dev branches of /code/internal/ and /code/public/, and often I want to search for a text string in those directories along with /code/tools/ (which has no branches). In these instances I run a command like this:

grep -I -r FooBar /code/internal/dev/ /code/public/dev/ /code/tools/

Additionally, sometimes I am only interested in certain file types. Then the command becomes:

grep -I -r FooBar /code/internal/dev/ /code/public/dev/ /code/tools/ | grep .c:\|.h

I usually forget this command between usages and end up having to relearn it. To alleviate that problem, I created a script - which I would appreciate feedback on :)

search() {
    local t
    local OPTIND
    local pattern
    local files
    local types
    
    if [ $1 = --help ]; then
        echo "Usage: search [OPTION] ... PATTERN [FILE] ..."
        echo "Search for PATTERN in each FILE."
        echo "Example: search -t c -t h 'hello world' /code/internal/dev/ /code/public/dev/"
        echo
        echo "Output control:"
        echo "  -t    limit results to files of type"
        return
    fi
    
    while getopts ":t:" opt; do
        case $opt in
            t) t=(${t[@]} $OPTARG);; # create an array
        esac
    done
    shift $((OPTIND-1))
    
    pattern=$1
    files=${@:2}
    
    if [ -n "$t" ]; then
        # cast the array to a string
        types=${t[@]}
        
        # convert the string to a pattern usable by grep
        # example: "c h" becomes ".c:\|.h:"
        types=.${types// /':\|.'}:
        
        grep -I -r $pattern $files | grep $types
    else
        grep -I -r $pattern $files
    fi
}

With this and a couple more shortcut scripts, I can (relatively) quickly find anything I'm looking for:

search-all-code() {
    search $@ /code/internal/dev/ /code/public/dev/ /code/tools/
}

Aside: I realize some versions of grep support --include and --exlude options, but the version of grep I'm stuck with doesn't.