path: root/mgrep
blob: d57f9b50e7a597b4283796914a3d4f08c11384b2 (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

# 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.
if [[ -r $conf ]] ; then
    source -- "$conf"

# Default to giving three lines of context in grep(1) output

# 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.

# The path through which find(1) will run to find files for grep(1) to search.
# Defaults to your $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"

# 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
            exit 0
            find_args=("${find_args[@]}" '-mtime' -"$OPTARG")
            printf '%s: Invalid option: -%s\n' "$self" "$OPTARG" >&2
            exit 1
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

# 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")

# 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")
    done < "$exclude"

# 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[@]}" \
        {} +