My favorite feature is:<p><pre><code> -P, --perl-regexp
Interpret I<PATTERNS> as Perl-compatible regular
expressions (PCREs). This option is experimental when
combined with the -z (--null-data) option, and grep -P
may warn of unimplemented features.
</code></pre>
As everything (python, Go, javascript, etc, etc) uses perl regexps now-a-days and I can never remember which things I need to escape for old gods regexp.
An amazing grep trick that I use all the time: The -e flag can be used to search for multiple terms. A blank -e will search for null. Thus:<p>Lets assume we have a log file with a bunch of relevant stuff, I want to highlight my search term, BUT I also want to keep all the other lines around for context:<p><pre><code> $ dmesg
...SNIP...
[2334597.539661] sd 1:0:0:0: [sdb] Attached SCSI removable disk
[2334597.548919] sd 1:0:0:0: [sdb] 57280429 512-byte logical blocks: (29.3 GB/27.3 GiB)
[2334597.761895] sd 1:0:0:0: [sdb] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[2334597.761900] sdb: detected capacity change from 0 to 57280429
[2334597.772736] sdb:
[2334631.115664] sdb: detected capacity change from 57280429 to 0
...SNIP...
</code></pre>
A simple grep, will only return the selected lines:<p><pre><code> $ dmesg | grep capacity
[2334597.761900] sdb: detected capacity change from 0 to 57280429
[2334631.115664] sdb: detected capacity change from 57280429 to 0
</code></pre>
But I want all lines:<p><pre><code> $ dmesg | grep --color -e capacity -e ''
...SNIP...
[2334597.539661] sd 1:0:0:0: [sdb] Attached SCSI removable disk
[2334597.548919] sd 1:0:0:0: [sdb] 57280429 512-byte logical blocks: (29.3 GB/27.3 GiB)
[2334597.761895] sd 1:0:0:0: [sdb] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
*[2334597.761900] sdb: detected capacity change from 0 to 57280429*
[2334597.772736] sdb:
*[2334631.115664] sdb: detected capacity change from 57280429 to 0*
...SNIP...
</code></pre>
The null trick also works well on directories with many small files, like <i>/proc/</i> or <i>/sys/</i>. Say, for example, you wanted to get the filename and value of each file:<p><pre><code> $ grep -R '' /sys/module/iwlwifi/parameters/
/sys/module/iwlwifi/parameters/nvm_file:(null)
/sys/module/iwlwifi/parameters/debug:0
/sys/module/iwlwifi/parameters/swcrypto:0
/sys/module/iwlwifi/parameters/power_save:N
/sys/module/iwlwifi/parameters/lar_disable:N
...SNIP...</code></pre>
><i>The -I flag only considers text files. This radically speeds up recursive greps.</i><p>I use ripgrep when I need better speed. I've pretty much switched to ripgrep these days, but still use GNU grep when I'm answering questions on stackoverflow, reddit, etc.<p>><i>ABC flags</i><p>Good to also know about `--group-separator` and `--no-group-separator` when there are multiple non-contiguous matches. Helps to customize the separator or remove them altogether. Sadly, these options are still not explained in `man grep` on Ubuntu. You'll have to use `info grep` or the online manual to find them.<p>Options I use often that is not mentioned in the article:<p>* `-c` to count the number of matches<p>* `-F` for fixed string matching<p>* `-x` to match whole lines<p>* `-P` for PCRE (as mentioned in many comments here)<p>* `--color=auto` this is part of command name alias, so it is always used<p>I wrote a book as well on "GNU grep and ripgrep": <a href="https://github.com/learnbyexample/learn_gnugrep_ripgrep" rel="nofollow">https://github.com/learnbyexample/learn_gnugrep_ripgrep</a> Free to read online.
I have a shell alias/function variations of which I've used for decades. This is the zsh version:<p><pre><code> function fvi { grep -rl $1 . | xargs nvim +/$1 }
</code></pre>
It greps a directory recursively and opens files which have a pattern and puts the pattern in the search buffer.
Here's how GNU grep detect binary files, good to know sometimes: <a href="https://unix.stackexchange.com/a/276028" rel="nofollow">https://unix.stackexchange.com/a/276028</a>
Learning about -o has decreased my use of sed considerably. Where I used to use:<p><pre><code> sed -n 's/.*\(pattern\).*/\1/p'
</code></pre>
it can instead simply be:<p><pre><code> grep -o 'pattern'
</code></pre>
The -w flag is new to me today - excited to save still more keystrokes!
I think I have never used grep -r. I'm sure gnu grep has some way to specify which files to search, but why would I learn that syntax as well when I already know find, and exec works (exec + is much faster, but exec ; gets you the results too if your find lacks exec +).
It's good to be aware that gnu grep has a lot more features than "unix" grep, so if you find yourself on a BSD system a lot of this stuff doesn't work.
It's weirdly difficult to get grep to search for fixed binary strings, with lots of gotchas if you don't understand grep internals. I still don't, but this is the best I have been able to do after knocking my forehead on three or four of said gotchas:<p><pre><code> LC_ALL=C grep -larP '\x1A\x2B\x3C\xFF'</code></pre>
Grep is nice and I've used it daily, but damn does it need multi threading! Especially for recursive greps. I find myself doing this a heck of a lot these days:<p><pre><code> find . -type f -name \*txt \; | xargs -I{} -P24 bash -c "grep -Hi foo '{}' ; :"</code></pre>
I have problems remembering the mnemonic for -A and -B. I can't get it straight whether it's "before" and "after" or "above" and "below". I always just try one then the other!
I looked for an option to specify a filelist (like ctags -L file) but didn't seem to find one. I'm assuming others are happy with using xargs or `cat file`, but it would seem like a useful feature.
very frequently I want to chain grep things... I lean on the "|" operator for this, e.g. cat hello | grep foo | grep bar and it seems verbose. any tips?
My grep is almost always:<p><pre><code> grep -nRI foo ./
</code></pre>
Sometimes I add `-i`<p>Often I will add `-P` and encase the regex with single-quotes of course
i've had this stuck to my office wall for a while, and i've internalized most of it by now but it's still great<p><a href="https://twitter.com/b0rk/status/991880504805871616" rel="nofollow">https://twitter.com/b0rk/status/991880504805871616</a>