Grep me out of here!
Grep helps you locate any given pattern(s) within one or more files.
Very useful when parsing logs!
Keep in mind
Not all Grep implementations are created equal.
This post references the GNU version, although hopefully most of the information is generic enough to be of use in most find implementations.
Basics
At the most basic level, Grep commands have the following structure:
grep 'this_string' that_file.md
This will output the full line(s) where this_string
was found, highlighting the match itself.
Throw a -n
in there to show the line Numbers as well.
Of course one could also grep all files in a given directory:
grep -n 'this_string' .
Would look for this_string
in all files in the directory where the command was launched but not in its child directories.
Speaking of which…
Not so Basics
Recurse
Say we want to grep recursively all child directories.
grep -rs 'this_string' .
Tells Grep to search Recursively in cwd
.
The output will be Silent, as in all warnings and errors messages will get Suppressed.
This is usually done to avoid useless errors when grepping directories (which will happen with -r
).
Multiple searches
Just like Sed, you can use -e
to concatenate multiple searches in the same Grep command.
Unlike Sed, this does not equate to multiple Grep commands piped together.
Rather, a Grep command with multiple -e
expressions will return any pattern that matches any of the expressions, while piping one command into another will only output whatever matches all expressions.
Suppose a grepme
file like so:
3183_22_4: option: '3183_22', question: '3183', suffix: '4'
3183_22_5: option: '3183_22', question: '3183', suffix: '5'
3283_23_1: option: '3183_23', '3183', suffix: '1'
3183_23_2: '3183_23', question: '3183', suffix: '2'
grep -e 'option' -e 'question' grepme
would output the whole file while grep 'option' grepme | grep 'question'
would only output:
3183_22_4: option: '3183_22', question: '3183', suffix: '4'
3183_22_5: option: '3183_22', question: '3183', suffix: '5'
To be clear: -e
matches any of the expressions while piping Grep commands together matches all the expressions.
Regex
Again, just like Sed and Find, Grep uses reduced regex by default and the -E
flag allows you to use its full regex engine.
If instead you want to avoid regex altogether and look for a literal string with strange characters, use -F
.
grep -F '[Hh]ello moto*' file
will literally match “[Hh]ello moto*”, not “Hello moto”, not “hello moto”, and not “[Hh]ello moto, how you doing?”.
Common use cases
The classics
|
|
The first command will output all lines plus lines numbers (-n
) NOT matching foo
(-v
). It will look for the match recursively (-rs
) in a cases Insensitive (-i
) fashion.
The second one will output all files containing a match (-l
, -L
would output only files NOT containing a match) for bar
, recursively (-rs
).
Count
More often than not you’ll need the number of matching lines, more so than the lines themselves.
You might be tempted to pipe Grep into wc -l
, but there’s no need to!
grep 'hi there!' file | wc -l
and grep -c 'hi there!' file
produce the same output: They both Count the number of matching lines.
Instead, use this pipe with the -o
flag to get the number of Ocurrances (which will differ from -c
if there is more than one match per line).
So following the example above:
grep -c '3183_22' grepme
➡️ 2
grep -o '3183_22' grepme | wc -l
➡️ 4
Whole
While -w
will match for whole words, -x
will match for whole lines:
So for grep -w 'opt' grepme
:
✅ blahblah opt blah
❌ blahblah option blah
While for grep -x 'opt' grepme
:
✅ opt
❌ blahblah opt blah
Fancy things you can do
Context
You might find it useful to have some Context around your Grep results.
Use something like -C2
to tell Grep to also print the two lines before and after each match.
Keep in mind that the amount of context lines printed will be limited by other matches as well as the beginning and end of the file.
It’s quite helpful to use this in combination with the -n
flag, since Grep uses :
to separate the matching lines from their line number and -
for context lines.
So given a grepme
file like so:
noise1
3183_22_4: option: '3183_22', question: '3183', suffix: '4'
noise2
3183_22_5: option: '3183_22', question: '3183', suffix: '5'
noise3
noise31
3283_23_1: option: '3183_23', '3183', suffix: '1'
noise4
3183_23_2: '3183_23', question: '3183', suffix: '2'
noise5
grep -nC2 '3183_22' grepme
will output
1-noise1
2:3183_22_4: option: '3183_22', question: '3183', suffix: '4'
3-noise2
4:3183_22_5: option: '3183_22', question: '3183', suffix: '5'
5-noise3
6-noise31
Exclude and include
You can exclude and include files from the search by a given pattern.
Even more fancy, you can use both flags together to fine tune where you are searching exactly.
grep --exclude=*.py --include=main.py 'anexpression' *
Will look in all non *.py
files (except for main.py
) in cwd
for anexpression
.
Grep based on a file
Say you have a list of blacklisted words you want to ensure are not present in a project.
grep -f unwantedWords.md projectFile
will print out all matches for any of the lines in blacklist.file
, while passing it the -l
flag from before will print only the problematic filenames.
For this example to make sense, we assume that unwantedWords.md
contains one expression or word per line.
Another neat use case:
find . | grep -f wantedFiles.md
Will output all filenames in cwd
listed in the file wantedFiles.md
.