Chapter 5: Text, editors and the shell environment

Search text with grep

grep prints the lines that match a pattern. It is the tool you will use most often after ls: to find a setting in a configuration file, an account in /etc/passwd, an error in a log, or one line in a command's long output. Its patterns are regular expressions, a small language worth learning properly once.

Find lines

grep PATTERN FILE… prints every line of the files that contains the pattern. Without a file, it reads stdin, which makes it the natural end of a pipe:

[student@servera ~]$ grep student /etc/passwd
student:x:1000:1000:Student User:/home/student:/bin/bash
[student@servera ~]$ ip -4 addr | grep inet
    inet 127.0.0.1/8 scope host lo
    inet 172.25.250.10/24 brd 172.25.250.255 scope global dynamic noprefixroute enp5s0

Put the pattern in single quotes whenever it contains anything other than letters and digits, so the shell passes it to grep untouched.

OptionDoes
-iIgnore case
-vInvert: print lines that do not match
-nNumber each printed line
-cPrint only how many lines matched
-wMatch whole words only
-rSearch every file below a directory
-lPrint only the names of files that match
-EExtended regular expressions (below)
[student@servera ~]$ grep -c nologin /etc/passwd
15
[student@servera ~]$ grep -n bash /etc/passwd
1:root:x:0:0:root:/root:/bin/bash
19:student:x:1000:1000:Student User:/home/student:/bin/bash
[student@servera ~]$ sudo grep -r PermitRootLogin /etc/ssh/
/etc/ssh/sshd_config:#PermitRootLogin prohibit-password
/etc/ssh/sshd_config:# the setting of "PermitRootLogin prohibit-password".

That last search needs sudo because the SSH server's configuration is readable only by root.

Regular expressions

A regular expression describes text. Most characters match themselves; a few are special:

ExpressionMatches
^The start of the line: ^# finds lines that begin with #
$The end of the line: 200$; ^$ is an empty line
.Any single character
*The item before it, repeated zero or more times: .* is "anything"
[abc], [0-9]One character from the set or range
[^abc]One character not in the set
[[:digit:]], [[:space:]], [[:alpha:]] …One character of a class
\<, \>The start or end of a word
\.A literal dot (any special character, escaped)

Extended expressions: grep -E

With -E, four more operators work directly:

ExpressionMatches
+The item before it, one or more times
?The item before it, zero or one time
{n}, {n,}, {n,m}Exactly n, at least n, or n to m times
<code>a|b</code>Either a or b
( )Groups items: <code>(INFO|WARN) +web01</code>

Without -E (basic syntax), the same operators need a backslash: \+, \?, \{n\}, \|, \( \). Most people simply use -E whenever a pattern needs them.

Try it

This tester reproduces grep exactly, including the basic and extended syntaxes. Choose a preset, change the pattern or the options, and watch which lines are selected and what grep prints:

Recipes you will use constantly

Show only the active lines of a configuration file, without comments or blank lines:

[student@servera ~]$ wc -l /etc/chrony.conf
50 /etc/chrony.conf
[student@servera ~]$ grep -Ev '^(#|$)' /etc/chrony.conf
pool 2.rocky.pool.ntp.org iburst
sourcedir /run/chrony-dhcp
driftfile /var/lib/chrony/drift
makestep 1.0 3
rtcsync
keyfile /etc/chrony.keys
ntsdumpdir /var/lib/chrony
leapsectz right/UTC
logdir /var/log/chrony

Fifty lines shrink to the nine that matter. Some other everyday searches:

QuestionCommand
Which accounts have UID 0?grep '^[^:]*:x:0:' /etc/passwd
Which files under /etc/ssh mention PasswordAuthentication?sudo grep -rl PasswordAuthentication /etc/ssh/
How many SSH key logins succeeded?sudo grep -c 'Accepted publickey' /var/log/secure
Is the httpd service mentioned in the log?sudo grep -i httpd /var/log/messages
Which lines of a big output mention eth?`COMMAND

Check your understanding