1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
#!/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
# 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[@]}" \
{} +
|