#!/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 # 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 # Try to change into the path for find(1). This is just to prevent long # prefixes in the output of `grep -h`. cd -- "$path" || exit # Run the find(1) command with its determined arguments, with an -exec option # calling grep(1) with its determined arguments. find ./* \ -type f \ "${find_args[@]}" \ -exec \ grep \ --color=auto \ --context="$context" \ --dereference-recursive \ --ignore-case \ --with-filename \ "${grep_args[@]}" \ {} +