aboutsummaryrefslogblamecommitdiff
path: root/mgrep
blob: 8469408f4d7247faf57984ac6cfeec4492a10e3f (plain) (tree)































































































                                                                               

                                                                             
              











                                 
#!/usr/bin/env bash

#
# GNU grep(1) wrapper to search for fixed patterns in a predefined directory
# recursively and quickly, intended for interactive use. I wrote this to search
# my IRC logs in a quick and lazy way, but you could use it for any sort of
# quick-recursive-grep interactive task, hopefully.
#
# "mgrep" is short for "my grep".
#
# Author: Tom Ryder <tom@sanctum.geek.nz>
# Copyright: 2015
# License: MIT
#
self=mgrep

# You will probably want to create an ~/.mgreprc to specify at least the path
# you want to search, unless it really is $HOME. Here's mine:
#
# context=3
# exclude=$HOME/.mgrep/exclude
# path=$HOME/Documents/Logs
#
# If you want, you can specify different paths by exporting MGREP_CONFIG.
#
conf=${MGREP_CONFIG:-$HOME/.${self}rc}
if [[ -r $conf ]] ; then
    source -- "$conf"
fi

# Default to giving three lines of context in grep(1) output
context=${context:-3}

# Path to filename containing a newline-separated list of exclusion patterns
# for filenames (not full paths) to be matched by find(1); this file will be
# silently ignored if nonexistent; bash(1) should raise an error if it exists
# but isn't readable; defaults to "$HOME"/.local/etc/mgrep/exclude.
exclude=${exclude:-$HOME/.$self/exclude}

# The path through which find(1) will run to find files for grep(1) to search.
# Defaults to your $HOME.
path=${path:-$HOME}

# Start lists of arguments for find(1) and grep(1)
declare -a find_args grep_args

# Output describing correct usage
usage() {
    printf 'Usage: %s [-h|-tN] PATTERN [PATTERN...]\n' \
        "$self" "$self"
}

# Look for the -t option, which optionally specifies an -mtime argument to
# find(1); that is, limit the search to only files modified in the last n days
while getopts 'ht:' opt ; do
    case $opt in
        h)
            usage
            exit 0
            ;;
        t)
            find_args=("${find_args[@]}" '-mtime' -"$OPTARG")
            ;;
        \?)
            printf '%s: Invalid option: -%s\n' "$self" "$OPTARG" >&2
            usage
            exit 1
            ;;
    esac
done
shift "$((OPTIND-1))"

# Bail usefully if there are no arguments left; we need at least one
if ! (($#)) ; then
    printf '%s: Need at least one argument\n' "$self" >&2
    usage >&2
    exit 1
fi

# Add --regexp patterns to the grep arguments for each command-line argument;
# this is an OR search, not an AND one, so most of the time you'll probably
# be specifying just one argument
for arg in "${@:?}" ; do
    grep_args=("${grep_args[@]}" '--regexp' "$arg")
done

# Attempt to read the exclusions file; if it exists, try to read exclusion
# patterns from it. If it doesn't exist, just continue on.
if [[ -e $exclude ]] ; then
    while read -r exclusion ; do
        if [[ $exclusion ]] ; then
            find_args=("${find_args[@]}" '!' '-name' "$exclusion")
        fi
    done < "$exclude"
fi

# Run the find(1) command with its determined arguments, with an -exec option
# calling grep(1) with its determined arguments.
find "$path" \
    -type f \
    "${find_args[@]}" \
    -exec \
        grep \
        --color=auto \
        --context="$context" \
        --dereference-recursive \
        --ignore-case \
        --with-filename \
        "${grep_args[@]}" \
        {} +