CrackOps
Interview PrepTracksLinuxAWS LabSoonInterview RoomSoon
Sign inStart free
CrackOps

Interview prep for the people who keep production up.

[email protected]
ProductInterview PrepTracksDashboardInterview Room
RolesDevOpsSREPlatformCloud
CompanyAboutContactPrivacyTerms
© CrackOps
Linux / Text Processing / grep

grep

Search text for lines that match a pattern

Beginneressentiallogsregexsearch

grep prints the lines of a file (or of a pipe) that match a pattern. It is the first tool you reach for in an incident: find the errors, see the lines around a crash, count failures, or find where a setting is defined across a whole code base.

Syntaxgrep [OPTION]... PATTERN [FILE]...

Watch it run

An alert says the orders API is unhealthy. You want every ERROR line, how many there are, and where the FATAL is.

devops@devops-lab: ~/logs — zsh — 96×28
➜ ~/logs
Step 1 of 3
grep ERROR app.log | head -4

grep prints every line containing ERROR; head keeps the first four. No colour here: grep only highlights matches when it writes straight to a terminal, not into a pipe.

Anatomy of a command

$
commandgrep

Global Regular Expression Print: prints every line that matches.

How it works

grep compiles the pattern once into a fast matcher: a Boyer-Moore style scan for fixed strings, a DFA for most regexes, and a slower backtracking engine only for back-references or -P. It then read()s the file in large chunks (tens of kilobytes) and searches the whole buffer at once; only when something matches does it look backwards and forwards for the newline characters that bound the line. That is why grep is far faster than reading line by line. If a chunk contains NUL bytes it treats the file as binary and prints 'binary file matches' instead of the line. The exit status is 0 if any line matched, 1 if none did and 2 on an error such as a missing file, which is what makes grep -q useful in if statements. When stdout is a pipe instead of a terminal, grep block-buffers its output, so tail -f | grep | other-command can look stuck until --line-buffered is added.

Options you'll actually use

-iIgnore case
-vInvert: print lines that do NOT match
-nShow line numbers
-cPrint only the number of matching lines (per file)
-l / -LPrint only names of files that match / that don't match
-r / -RSearch directories recursively (-R also follows symlinks)
-wMatch whole words only (error, not errors or error_count)
-EExtended regex: a|b, (x)+, [0-9]{3} without backslashes
-FFixed string, no regex: dots and brackets are literal (fast for IPs)
-oPrint only the matched part, one per line (great before sort | uniq -c)
-A N / -B N / -C NShow N lines After / Before / around each match
-m NStop after N matching lines
-qQuiet: print nothing, just set the exit status (for scripts)
--include / --exclude-dirWith -r, limit files by glob or skip directories like .git or node_modules

Common mistakes

grep 10.0.2.1 access.log to find one IP

The dot is a regex wildcard, so it also matches 10.0.231 or 10.0.2.11, 10.0.2.12 ... and you get the wrong lines.

grep -Fw '10.0.2.1' access.log # -F literal, -w whole word
tail -f app.log | grep ERROR | tee errors.txt (and nothing appears)

When grep writes into a pipe it block-buffers (a few KB) before flushing, so matches arrive late or seem never to come.

tail -f app.log | grep --line-buffered ERROR | tee errors.txt
ps aux | grep nginx (the grep shows up in its own results)

The grep process's own command line contains 'nginx', so it matches itself and scripts count one process too many.

pgrep -a nginx # or: ps aux | grep '[n]ginx'
grep -r password /

Recursing from / walks /proc, /sys and every mount: it takes ages, prints thousands of permission errors and may hang on device files.

grep -rn --exclude-dir={.git,node_modules} password /etc/myapp ~/app
grep ERROR app.log.*.gz to search rotated logs

The files are compressed: grep searches the gzip bytes and silently finds nothing (or prints 'binary file matches').

zgrep ERROR app.log.*.gz

Interview questions

Practice

Try these on a Linux machine of your own. Each task has a hint and a solution.

  1. 1

    Count how many lines in ~/logs/app.log contain ERROR (in any case).

  2. 2

    Show every line in ~/logs/app.log that is NOT INFO or DEBUG, with line numbers.

  3. 3

    Print the 3 lines before and after the first FATAL or CRITICAL line in any log under /var/log/app.

  4. 4

    List only the names of files under ~/app that mention 'password' (any case), skipping .git.

  5. 5

    Write a one-liner that prints 'DOWN' if /var/log/app has no line containing 'healthy'.

Related commands

sedStream editor: find and replace, delete and print linesawkProcess text by columns: filter, sum, count and reporttailShow the last lines of a file and follow it livefindSearch the filesystem by name, size, age, owner and morebash: exit codesExit codes, $?, set -euo pipefail and trap
PrevioustypeNextsed
Linux / Text Processing / grep

grep

Search text for lines that match a pattern

Beginneressentiallogsregexsearch

grep prints the lines of a file (or of a pipe) that match a pattern. It is the first tool you reach for in an incident: find the errors, see the lines around a crash, count failures, or find where a setting is defined across a whole code base.

Syntaxgrep [OPTION]... PATTERN [FILE]...

Watch it run

An alert says the orders API is unhealthy. You want every ERROR line, how many there are, and where the FATAL is.

devops@devops-lab: ~/logs — zsh — 96×28
➜ ~/logs
Step 1 of 3
grep ERROR app.log | head -4

grep prints every line containing ERROR; head keeps the first four. No colour here: grep only highlights matches when it writes straight to a terminal, not into a pipe.

Anatomy of a command

$
commandgrep

Global Regular Expression Print: prints every line that matches.

How it works

grep compiles the pattern once into a fast matcher: a Boyer-Moore style scan for fixed strings, a DFA for most regexes, and a slower backtracking engine only for back-references or -P. It then read()s the file in large chunks (tens of kilobytes) and searches the whole buffer at once; only when something matches does it look backwards and forwards for the newline characters that bound the line. That is why grep is far faster than reading line by line. If a chunk contains NUL bytes it treats the file as binary and prints 'binary file matches' instead of the line. The exit status is 0 if any line matched, 1 if none did and 2 on an error such as a missing file, which is what makes grep -q useful in if statements. When stdout is a pipe instead of a terminal, grep block-buffers its output, so tail -f | grep | other-command can look stuck until --line-buffered is added.

Options you'll actually use

-iIgnore case
-vInvert: print lines that do NOT match
-nShow line numbers
-cPrint only the number of matching lines (per file)
-l / -LPrint only names of files that match / that don't match
-r / -RSearch directories recursively (-R also follows symlinks)
-wMatch whole words only (error, not errors or error_count)
-EExtended regex: a|b, (x)+, [0-9]{3} without backslashes
-FFixed string, no regex: dots and brackets are literal (fast for IPs)
-oPrint only the matched part, one per line (great before sort | uniq -c)
-A N / -B N / -C NShow N lines After / Before / around each match
-m NStop after N matching lines
-qQuiet: print nothing, just set the exit status (for scripts)
--include / --exclude-dirWith -r, limit files by glob or skip directories like .git or node_modules

Common mistakes

grep 10.0.2.1 access.log to find one IP

The dot is a regex wildcard, so it also matches 10.0.231 or 10.0.2.11, 10.0.2.12 ... and you get the wrong lines.

grep -Fw '10.0.2.1' access.log # -F literal, -w whole word
tail -f app.log | grep ERROR | tee errors.txt (and nothing appears)

When grep writes into a pipe it block-buffers (a few KB) before flushing, so matches arrive late or seem never to come.

tail -f app.log | grep --line-buffered ERROR | tee errors.txt
ps aux | grep nginx (the grep shows up in its own results)

The grep process's own command line contains 'nginx', so it matches itself and scripts count one process too many.

pgrep -a nginx # or: ps aux | grep '[n]ginx'
grep -r password /

Recursing from / walks /proc, /sys and every mount: it takes ages, prints thousands of permission errors and may hang on device files.

grep -rn --exclude-dir={.git,node_modules} password /etc/myapp ~/app
grep ERROR app.log.*.gz to search rotated logs

The files are compressed: grep searches the gzip bytes and silently finds nothing (or prints 'binary file matches').

zgrep ERROR app.log.*.gz

Interview questions

Practice

Try these on a Linux machine of your own. Each task has a hint and a solution.

  1. 1

    Count how many lines in ~/logs/app.log contain ERROR (in any case).

  2. 2

    Show every line in ~/logs/app.log that is NOT INFO or DEBUG, with line numbers.

  3. 3

    Print the 3 lines before and after the first FATAL or CRITICAL line in any log under /var/log/app.

  4. 4

    List only the names of files under ~/app that mention 'password' (any case), skipping .git.

  5. 5

    Write a one-liner that prints 'DOWN' if /var/log/app has no line containing 'healthy'.

Related commands

sedStream editor: find and replace, delete and print linesawkProcess text by columns: filter, sum, count and reporttailShow the last lines of a file and follow it livefindSearch the filesystem by name, size, age, owner and morebash: exit codesExit codes, $?, set -euo pipefail and trap
PrevioustypeNextsed