0% found this document useful (0 votes)
11 views23 pages

Grep Operations: A Step-by-Step Guide

Uploaded by

Youssef.Rabei
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
11 views23 pages

Grep Operations: A Step-by-Step Guide

Uploaded by

Youssef.Rabei
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Table of contents

Introduction
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .3. . . . . . . . .
Preface

1. Basics
.Search
. . . . . .in
. .file
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .4. . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .5. . . . . . . . .
Matches
. . . . . . . .expressions
Regular . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .6. . . . . . . . .
. . . . . .strings
Fixed . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .8. . . . . . . . .
. . . . . . . .patterns
Multiple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .9. . . . . . . . .

2. Recursive search
.Search
. . . . . .in
. .directory
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .10
..........
. . . .globs
File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .11
..........
. . . . . . files
Binary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .13
..........

3. Search options
.Ignore
. . . . . case
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .14
..........
. . . . . . . matching
Inverse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .15
..........

4. Output options
.Count
. . . . . matches
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .16
..........
. . . . . matches
Limit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .17
..........
. . . . . .matches
Show . . . . . . . .only
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .18
..........
. . . . . .files
Show . . . .only
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .18
..........
. . . . . .context
Show . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .19
..........
. . . . . .mode
Silent . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .21
..........
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .22
Colors ..........

. . . . . thoughts
Final . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .23
..........

TABLE OF CONTENTS 2
Preface
grep is the ultimate text search tool available on virtually all Linux machines.
While there are now better alternatives (such as ripgrep ), you will still often
find yourself on a server where grep is the only search tool available. So it’s
nice to have a working knowledge of it.

That’s why is I’ve created this step-by-step guide to grep operations. You can
read it from start to finish to (hopefully) learn more about grep, or jump to a
specific use case that interests you.

You can try all the examples from this guide in the interactive playground.

Licensed under CC BY-NC-ND


Anton Zhiyanov, 2024

PREFACE 3
1. Basics
Basically, grep works like this:
• You give it a search pattern and a file.
• grep reads the file line by line, printing the lines that match the pattern
and ignoring others.

Let’s look at an example. We’ll search the httpurr source code, which I’ve al‐
ready downloaded to the /opt/httpurr directory.

Search in file
Let’s find all occurrences of the word codes in [Link] :

grep -n codes [Link]

3: <strong><i> >& HTTP status codes on speed dial <( <)i><)str


30:* List the HTTP status codes:
54:* Filter the status codes by categories:
124: Print HTTP status codes by category with -#list;
131: Print HTTP status codes

grep read the contents of [Link] , and for each line that contained codes ,
grep printed it to the terminal.

grep also included the line number for each line, thanks to the -n
( -#line-number ) option.

Not all grep versions support the long option syntax


(e.g. -#line-number ). If you get an error using the long ver‐
sion, try the short one (e.g. -n ) — it may work fine.

BASICS 4
Matches
grep uses partial matches by default:

grep -n descr [Link]

81:* Display the description of a status code:


127: Print the description of an HTTP status code

The word description matches the descr search pattern.

To search for whole words instead, use the -w ( -#word-regexp ) option:

grep -n -#word-regexp code [Link]

81:* Display the description of a status code:


84: httpurr -#code 410
94: Transfer Protocol (HTTP) 410 Gone client error response code
99: code should be used instead.
126: -c, -#code [status code]
127: Print the description of an HTTP status code

grep found strings containing the word code , but not codes . Try removing
-#word-regexp and see how the results change.

When using multiple short options, you can combine them


like this: grep -nw code [Link] . This gives exactly the
same result as using the separate options ( -n -w ).

To search for whole lines instead of partial matches of whole words, use the
-x ( -#line-regexp ) option:

grep -n -#line-regexp end [Link]

47:end

BASICS 5
Regular expressions
To make grep use regular expressions (Perl-compatible regular expressions in
grep terminology), use the -P ( -#perl-regexp ) option.

Let’s find all lines with a word that contains res followed by other letters:

grep -Pn 'res\w+' [Link]

94: Transfer Protocol (HTTP) 410 Gone client error response code
95: indicates that access to the target resource is no longer ava
152:of the rest.

\w+ means “one or more word-like characters” (e.g. letters like p or o , but
not punctuation like . or ! ), so response , resource , and rest all match.

Regular expression dialects in grep

Without -#perl-regexp , grep treats the search pattern as


something called a basic regular expression. While regular ex‐
pressions are quite common in the software world, the basic
dialect is really weird, so it’s better not to use it at all.

Another dialect supported by grep is extended regular expres‐


sions. You can use the -E ( -#extended-regexp ) option to
enable them. Extended regular expressions are almost like
normal regular expressions, but not quite. So I wouldn’t use
them either.

Some grep versions do not support -#perl-regexp . For


those, -#extended-regexp is the best you can get.

Suppose we are only interested in 4 letter words starting with res :

grep -Pn 'res\w\b' [Link]

BASICS 6
152:of the rest.

\b means “word boundary” (e.g. a space, a punctuation character, or the end


of a line), so rest matches, but response and resource don’t.

Finally, let’s search for 3-digit numbers (showing first 10 matches with head ):

grep -Pn '\d\d\d' [Link] | head

45: 100 Continue


46: 101 Switching Protocols
47: 102 Processing
48: 103 Early Hints
69: 200 OK
70: 201 Created
71: 202 Accepted
72: 203 Non-Authoritative Information
73: 204 No Content
74: 205 Reset Content

A full tutorial on regular expressions is beyond the scope of this guide, but
grep’s “Perl-compatible” syntax is documented in the PCRE2 manual.

BASICS 7
Fixed strings
What if we want to search for a literal string instead of a regular expression?
Suppose we are interested in a word code followed by a dot:

grep -Pn 'code.' src/[Link] | head

8:The HTTP 100 Continue informational status response code indica


14:status code in response before sending the body.
31:The HTTP 101 Switching Protocols response code indicates a pro
53:Deprecated: This status code is deprecated. When used, clients
56:The HTTP 102 Processing informational status response code ind
59:This status code is only sent if the server expects the reques
112:The HTTP 200 OK success status response code indicates that t
141:The HTTP 201 Created success status response code indicates t
149:The common use case of this status code is as the result of a
165:The HTTP 202 Accepted response status code indicates that the

Since . means “any character” in regular expressions, our pattern also


matches code , codes and other cases we are not interested in.

To treat the pattern as a literal string, use the -F ( -#fixed-strings ) option:

grep -Fn 'code.' src/[Link]

197:to responses with any status code.


283:accessing web pages will never encounter this status code.
695:to an error code.
1027:happens, they will handle it as a generic 400 status code.
1051:web servers will normally not return this status code. But s
1418:then the server responds with the 510 status code.

Much better!

BASICS 8
Multiple patterns
To search for multiple patterns, list them with the -e ( -#regexp ) option.
grep will output lines matching at least one of the specified patterns.

For example, search for make or run :

grep -En -e make -e run [Link]

139:* Go to the root directory and run:


141: make init
145: make lint
149: make test

Unfortunately, grep can’t use Perl-compatible regular expres‐


sions ( -P ) with multiple patterns. So we are stuck with the
extended ( -E ) dialect.

If you have many patterns, it may be easier to put them in a file and point grep
to it with -f ( -#file ):

echo 'install' > /tmp/[Link]


echo 'make' >& /tmp/[Link]
echo 'run' >& /tmp/[Link]

grep -En -#file=/tmp/[Link] [Link]

13:* On MacOS, brew install:


17: &. brew install httpurr
20:* Or elsewhere, go install:
23: go install [Link]/rednafi/httpurr/cmd/httpurr
139:* Go to the root directory and run:
141: make init
145: make lint
149: make test

BASICS 9
2. Recursive search
grep searches directories recursively when called with the -r ( -#recursive )
option.

Search in directory
Let’s find all unexported functions (they start with a lowercase letter):

grep -Pnr 'func [a-z]\w+' .

./cmd/httpurr/[Link]:func main() {
./src/[Link]:func formatStatusText(text string) string {
./src/[Link]:func printHeader(w *[Link]) {
./src/[Link]:func printStatusCodes(w *[Link], catego
./src/[Link]:func printStatusText(w *[Link], code s

This search returned matches from both the cmd and src directories. If you
are only interested in cmd , specify it instead of . :

grep -Pnr 'func [a-z]\w+' cmd

cmd/httpurr/[Link]:func main() {

To search multiple directories, list them all like this:

grep -Pnr 'func [a-z]\w+' cmd src

cmd/httpurr/[Link]:func main() {
src/[Link]:func formatStatusText(text string) string {
src/[Link]:func printHeader(w *[Link]) {
src/[Link]:func printStatusCodes(w *[Link], category
src/[Link]:func printStatusText(w *[Link], code str

RECURSIVE SEARCH 10
File globs
Let’s search for httpurr :

grep -Pnr -#max-count=5 httpurr .

./[Link]: <h1>ᗢ httpurr<)h1>


./[Link]: brew tap rednafi/httpurr https:/[Link]/redna
./[Link]: &. brew install httpurr
./[Link]: go install [Link]/rednafi/httpurr/cmd/httpurr
./[Link]: httpurr -#list
./cmd/httpurr/[Link]: "[Link]/rednafi/httpurr/src"
./[Link]:module [Link]/rednafi/httpurr
./[Link]: homepage "https:/[Link]/rednafi/httpurr"
./[Link]: url "https:/[Link]/rednafi/httpurr/rel
./[Link]: [Link] "httpurr"
./[Link]: url "https:/[Link]/rednafi/httpurr/rel
./[Link]: [Link] "httpurr"
./src/[Link]: [Link](w, "\nᗢ httpurr\n")
./src/cli_test.go:64: want :3 "\nᗢ httpurr\n==========\n\n"

Note that I have limited the number of results per file to 5 with the -m
( -#max-count ) option to keep the results readable in case there are many
matches.

Quite a lot of results. Let’s narrow it down by searching only in .go files:

grep -Pnr -#include='*.go' httpurr .

./cmd/httpurr/[Link]: "[Link]/rednafi/httpurr/src"
./src/[Link]: [Link](w, "\nᗢ httpurr\n")
./src/cli_test.go:64: want :3 "\nᗢ httpurr\n==========\n\n"

The -#include option (there is no short version) takes a glob (filename pat‐
tern), typically containing a fixed part ( .go in our example) and a wildcard *
(“anything but the path separator”).

RECURSIVE SEARCH 11
Another example — search in files named http -something:

grep -Pnr -#include='http*' httpurr .

./[Link]: homepage "https:/[Link]/rednafi/httpurr"


./[Link]: url "https:/[Link]/rednafi/httpurr/rel
./[Link]: [Link] "httpurr"
./[Link]: url "https:/[Link]/rednafi/httpurr/rel
./[Link]: [Link] "httpurr"
./[Link]: url "https:/[Link]/rednafi/httpurr/rel
./[Link]: [Link] "httpurr"
./[Link]: url "https:/[Link]/rednafi/httpurr/rel
./[Link]: [Link] "httpurr"

To negate the glob, use the -#exclude option. For example, search every‐
where except the .go files:

grep -Pnr -#exclude '*.go' def .

./.[Link]:# [Link] file with some sensible defaults.


./[Link]: def install
./[Link]: sha256 "82adefd1222f6228636f2cda6518e0316f4
./[Link]: def install
./[Link]: def install
./[Link]: def install

To apply multiple filters, specify multiple glob options. For example, find all
functions except those in test files:

grep -Pnr -#include '*.go' -#exclude '*_test.go' 'func ' .

./cmd/httpurr/[Link]:func main() {
./src/[Link]:func formatStatusText(text string) string {
./src/[Link]:func printHeader(w *[Link]) {
./src/[Link]:func printStatusCodes(w *[Link], catego
./src/[Link]:func printStatusText(w *[Link], code s
./src/[Link]:func Cli(w *[Link], version string, ex

RECURSIVE SEARCH 12
Binary files
By default, grep does not ignore binary files:

grep -Pnr aha .

grep: ./[Link]: binary file matches

Most of the time, this is probably not what you want. If you’re searching in a
directory that might contain binary files, it’s better to ignore them altogether
with the -I ( -#binary-files=without-match ) option:

grep -Pnr -#binary-files=without-match aha .

(not found)

If for some reason you want grep to search binary files and print the actual
matches (as it does with text files), use the -a ( -#text ) option.

RECURSIVE SEARCH 13
3. Search options
grep supports a couple of additional search options you may find handy.

Ignore case
Let’s find all occurrences of the word codes in [Link] :

grep -Pnr codes [Link]

3: <strong><i> >& HTTP status codes on speed dial <( <)i><)str


30:* List the HTTP status codes:
54:* Filter the status codes by categories:
124: Print HTTP status codes by category with -#list;
131: Print HTTP status codes

It returns codes matches, but not Codes because grep is case-sensitive by


default. To change this, use -i ( -#ignore-case ):

grep -Pnr -#ignore-case codes [Link]

3: <strong><i> >& HTTP status codes on speed dial <( <)i><)str


30:* List the HTTP status codes:
40: Status Codes
54:* Filter the status codes by categories:
64: Status Codes
124: Print HTTP status codes by category with -#list;
131: Print HTTP status codes

SEARCH OPTIONS 14
Inverse matching
To find lines that do not contain the pattern, use -v ( -#invert-match ). For
example, find the non-empty lines without the @ symbol:

grep -Enr -#invert-match -e '@' -e '^$' Makefile

1:.PHONY: lint
2:lint:
8:.PHONY: lint-check
9:lint-check:
14:.PHONY: test
15:test:
20:.PHONY: clean
21:clean:
27:.PHONY: init
28:init:

SEARCH OPTIONS 15
4. Output options
grep supports a number of additional output options you may find handy.

Count matches
To count the number of matched lines (per file), use -c ( -#count ). For ex‐
ample, count the number of functions in each .go file:

grep -Pnr -#count -#include '*.go' 'func ' .

./cmd/httpurr/[Link]
./src/[Link]
./src/cli_test.go:10
./src/data_test.go:2

Note that -#count counts the number of lines, not the number of matches.
For example, there are 6 words string in src/[Link] , but two of them are
on the same line, so -#count reports 5:

grep -nrw -#count string src/[Link]

OUTPUT OPTIONS 16
Limit matches
To limit the number of matching lines per file, use the -m ( -#max-count ) op‐
tion:

grep -Pnrw -#max-count=5 func .

./cmd/httpurr/[Link]:func main() {
./src/[Link]:func formatStatusText(text string) string {
./src/[Link]:func printHeader(w *[Link]) {
./src/[Link]:func printStatusCodes(w *[Link], catego
./src/[Link]:func printStatusText(w *[Link], code s
./src/[Link]:func Cli(w *[Link], version string, ex
./src/cli_test.go:15:func TestFormatStatusText(t *testing.T) {
./src/cli_test.go:54:func TestPrintHeader(t *testing.T) {
./src/cli_test.go:71:func TestPrintStatusCodes(t *testing.T) {
./src/cli_test.go:159: [Link](want, func(t *testing.T) {
./src/cli_test.go:168:func TestPrintStatusText(t *testing.T) {
./src/data_test.go:9:func TestStatusCodes(t *testing.T) {
./src/data_test.go:99:func TestStatusCodeMap(t *testing.T) {

With -#max-count=N , grep stops searching the file after finding the first N
matching lines (or non-matching lines if used with -#invert-match ).

OUTPUT OPTIONS 17
Show matches only
By default, grep prints the entire line containing the match. To show only the
matching part, use -o ( -#only-matching ).

Suppose we want to find functions named print -something:

grep -Pnr -#only-matching -#include '*.go' 'func print\w+' .

./src/[Link]:func printHeader
./src/[Link]:func printStatusCodes
./src/[Link]:func printStatusText

The results are much cleaner than without -#only-matching (try removing
the option in the above command and see for yourself).

Show files only


If there are too many matches, you may prefer to show only the files where
the matches occurred. Use -l ( -#files-with-matches ) to do this:

grep -Pnr -#files-with-matches 'httpurr' .

./[Link]
./cmd/httpurr/[Link]
./[Link]
./[Link]
./src/[Link]
./src/cli_test.go

OUTPUT OPTIONS 18
Show context
Let’s search for GitHub action jobs:

grep -Pnr 'jobs:' .github/workflows

.github/workflows/[Link]:jobs:
.github/workflows/[Link]:jobs:
.github/workflows/[Link]:jobs:
.github/workflows/[Link]:jobs:

These results are kind of useless, because they don’t return the actual job
name (which is on the next line after jobs ). To fix this, let’s use -C
( -#context ), which shows N lines around each match:

grep -Pnr -#context=1 'jobs:' .github/workflows

.github/workflows/[Link]-7-
.github/workflows/[Link]:jobs:
.github/workflows/[Link]-9- dependabot:
-#
.github/workflows/[Link]-10-
.github/workflows/[Link]:jobs:
.github/workflows/[Link]-12- golangci:
-#
.github/workflows/[Link]-9-
.github/workflows/[Link]:jobs:
.github/workflows/[Link]-11- goreleaser:
-#
.github/workflows/[Link]-10-
.github/workflows/[Link]:jobs:
.github/workflows/[Link]-12- test:

It might be even better to show only the next line after the match, since we are
not interested in the previous one. Use -A ( -#after-context ) for this:

grep -Pnr -#after-context=1 'jobs:' .github/workflows

OUTPUT OPTIONS 19
.github/workflows/[Link]:jobs:
.github/workflows/[Link]-9- dependabot:
-#
.github/workflows/[Link]:jobs:
.github/workflows/[Link]-12- golangci:
-#
.github/workflows/[Link]:jobs:
.github/workflows/[Link]-11- goreleaser:
-#
.github/workflows/[Link]:jobs:
.github/workflows/[Link]-12- test:

There is also -B ( -#before-context ) for showing N lines be‐


fore the match.

Nice!

OUTPUT OPTIONS 20
Silent mode
Sometimes you just want to know if a file contains a certain string; you don’t
care about the number or positions of the matches.

To make grep quit immediately after the first match and not print anything,
use the -q ( -#quiet or -#silent ) option. Use the return code ( $? ) to see if
grep found anything (0 — found, 1 — not found):

grep -Pnrw -#quiet main cmd/httpurr/[Link]


if [ $? = "0" ]; then echo "found!"; else echo "not found"; fi

found!

Try changing the search pattern from main to Main and see how the results
change.

When searching in multiple files with -#quiet , grep stops after the first
match in any file and does not check other files:

grep -Pnrw -#quiet main .


if [ $? = "0" ]; then echo "found!"; else echo "not found"; fi

found!

OUTPUT OPTIONS 21
Colors
To highlight matches and line numbers, use the -#color=always option:

grep -Pnr -#color=always codes [Link]

3: <strong><i> >& HTTP status codes on speed dial <( <)i><)str


30:* List the HTTP status codes:
54:* Filter the status codes by categories:
124: Print HTTP status codes by category with -#list;
131: Print HTTP status codes

Use -#color=auto to let grep decide whether to use colors based on your ter‐
minal. Use -#color=never to force no-color mode.

OUTPUT OPTIONS 22
Final thoughts
That’s it! We’ve covered just about everything grep can do. Unfortunately, it
doesn’t support replacing text, reading options from a configuration file, or
other fancy features provided by grep alternatives like ack or ripgrep . But
grep is still quite powerful, as you can probably see now.

If you find this book useful — please spread the word and subscribe to my
other projects at [Link]/subscribe.

Have fun grepping!

FINAL THOUGHTS 23

You might also like