Searching Text with grep
grep searches text for lines that match a pattern and prints them. It is probably the command you will use most after ls and cd, because so much of Linux is text: logs, configuration files, CSV data and source code.
In this lesson you will search a web server log and an SSH login log for useful facts, learn the options that matter, and write simple regular expressions (patterns that describe text) to find things like IP addresses and error codes.
Basic search
The form is grep PATTERN FILE.... grep prints every line that contains the pattern. Priya's server keeps SSH login messages in auth.log:
grep "Failed password" auth.log2026-10-30T06:12:01.102341+05:30 shop-server sshd[1201]: Failed password for root from 192.0.2.55 port 51122 ssh2 2026-10-30T06:12:04.551203+05:30 shop-server sshd[1201]: Failed password for root from 192.0.2.55 port 51122 ssh2 2026-10-30T06:13:40.008812+05:30 shop-server sshd[1230]: Failed password for invalid user admin from 198.51.100.89 port 40210 ssh2 2026-10-30T08:44:09.661270+05:30 shop-server sshd[1411]: Failed password for invalid user test from 198.51.100.89 port 40388 ssh2
Put the pattern in quotes whenever it contains spaces or special characters, otherwise the shell splits it into separate arguments. Single quotes are safest, because the shell changes nothing inside them.
The options you will use every day
| Option | Meaning |
|---|---|
-i | Ignore upper/lower case |
-n | Show line numbers |
-c | Count matching lines instead of printing them |
-v | Invert: show lines that do not match |
-w | Match whole words only |
-o | Print only the matching part, not the whole line |
-r | Search every file in a directory tree |
-l | List only the names of files that match |
-A n, -B n, -C n | Show n lines after, before, or around each match |
-F | Treat the pattern as plain text, not a regular expression |
grep -c "Failed password" auth.log
grep -v " 200 " access.log
grep -w "Pen" orders.csv4 192.0.2.55 - - [29/Oct/2026:10:03:02 +0530] "GET /wp-login.php HTTP/1.1" 404 162 "-" "curl/8.5.0" 192.0.2.55 - - [29/Oct/2026:10:03:03 +0530] "GET /.env HTTP/1.1" 404 162 "-" "curl/8.5.0" 198.51.100.23 - - [29/Oct/2026:10:05:30 +0530] "POST /order HTTP/1.1" 201 87 "-" "Mozilla/5.0" 192.0.2.55 - - [29/Oct/2026:10:06:45 +0530] "GET /admin HTTP/1.1" 404 162 "-" "curl/8.5.0" 203.0.113.7 - - [29/Oct/2026:10:09:20 +0530] "GET /order HTTP/1.1" 500 310 "-" "Mozilla/5.0" 1002,Priya,Jaipur,Pen Set,250 1007,Farhan,Pune,Pen Set,250
There were four failed logins. -v " 200 " hides every successful request, leaving only the interesting ones: one address probing for /wp-login.php, /.env and /admin (typical bot scanning) and one server error (500). -w "Pen" matches the word "Pen" but would not match "Pencil" or "Open".
Searching many files
-r searches a whole directory tree and prefixes each match with the file name. -l prints only the file names, which is perfect for "which config file sets this?":
grep -r "listen" site-config
grep -rl "8080" site-config
grep -rn "server_name" /etc/nginx/sites-availablesite-config/blog.conf:listen 8080; site-config/shop.conf:listen 80; site-config/blog.conf /etc/nginx/sites-available/shop:4: server_name shop.example.in;
Combine -r with -i and -n and you have a fast search tool for any project. Add --include='*.conf' to search only matching file names.
Context around a match
A log line rarely tells the whole story. -A 1 (after) shows the next line too, -B shows lines before, and -C both:
grep -A 1 "Accepted" auth.log2026-10-30T07:02:15.774410+05:30 shop-server sshd[1302]: Accepted publickey for priya from 203.0.113.7 port 55012 ssh2: ED25519 SHA256:q3Xr9mJb0eL2vKcR8sTnYpWz4uHaD1fG6iOkB7xVyZw 2026-10-30T07:02:15.790021+05:30 shop-server sshd[1302]: pam_unix(sshd:session): session opened for user priya(uid=1000) by priya(uid=0)
Regular expressions
A regular expression (regex) is a pattern language for text. By default grep uses basic regular expressions; grep -E switches on extended ones, where +, ?, {}, | and () work without backslashes. Use -E and you will rarely be surprised.
| Pattern | Matches |
|---|---|
^text | "text" at the start of a line |
text$ | "text" at the end of a line |
. | Any single character |
[0-9] | One digit; [a-z] one lower-case letter |
[^,] | Any character except a comma |
x* / x+ / x? | Zero or more / one or more / zero or one x |
x{3} / x{1,3} | Exactly three / one to three x |
cat|dog | "cat" or "dog" (needs -E) |
\. | A real dot, not "any character" |
Two practical examples: find every request that ended in a 4xx or 5xx error, then pull out every IP address in the SSH log and count them.
grep -E '" (4|5)[0-9]{2} ' access.log | cut -d' ' -f1,7,9
grep -Eo '([0-9]{1,3}\.){3}[0-9]{1,3}' auth.log | sort | uniq -c | sort -rn192.0.2.55 /wp-login.php 404
192.0.2.55 /.env 404
192.0.2.55 /admin 404
203.0.113.7 /order 500
2 198.51.100.89
2 192.0.2.55
1 203.0.113.7The first pattern means: a closing quote, a space, a 4 or a 5, exactly two more digits, then a space. That is exactly where the status code sits in a web log line. The second matches four groups of 1 to 3 digits separated by dots, and -o prints only that part of each line.
Old and new
You may see egrep and fgrep in older scripts and books. They were short names for grep -E and grep -F. Current GNU grep prints a warning such as "egrep: warning: egrep is obsolescent" when you use them, so write grep -E and grep -F instead. For very large code bases, many developers now use ripgrep (rg, installed with sudo apt install ripgrep), which searches folders recursively by default, skips files listed in .gitignore and is very fast. Plain grep is still the tool that is installed everywhere.
Common mistakes
- Forgetting quotes.
grep Failed password auth.logsearches for "Failed" in the filespasswordandauth.log. - Using
.to mean a dot.grep "192.0.2.5"also matches192x0y2z5. Escape it as192\.0\.2\.5, or use-Ffor plain text. - Expecting
+or|to work without-E. In basic mode they are ordinary characters. - Searching binary files. grep prints "binary file matches" instead of lines. Add
-aonly if you really need the text.
Key points
grep PATTERN FILEprints matching lines; quote the pattern.-iignores case,-nnumbers lines,-ccounts,-vinverts,-wmatches words,-oprints only the match.-rsearches folders,-llists matching files,-A/-B/-Cadd context.- Use
grep -Efor extended regular expressions:^,$,[],+,?,{n},|,(). - Use
grep -E/grep -F, not the obsoleteegrep/fgrep.
Exercise
Using access.log in the format shown above, write commands that: count the requests that came from 203.0.113.7; list only the lines for POST requests; show every request whose path ends in .html; and print the line number of every 404 response.
Show solution
grep -c '^203\.0\.113\.7 ' access.log
grep '"POST ' access.log
grep -E '\.html HTTP' access.log
grep -n '" 404 ' access.log4 198.51.100.23 - - [29/Oct/2026:10:05:30 +0530] "POST /order HTTP/1.1" 201 87 "-" "Mozilla/5.0" 198.51.100.23 - - [29/Oct/2026:10:01:15 +0530] "GET /menu.html HTTP/1.1" 200 3301 "-" "Mozilla/5.0" 203.0.113.7 - - [29/Oct/2026:10:06:11 +0530] "GET /contact.html HTTP/1.1" 200 2048 "-" "Mozilla/5.0" 4:192.0.2.55 - - [29/Oct/2026:10:03:02 +0530] "GET /wp-login.php HTTP/1.1" 404 162 "-" "curl/8.5.0" 5:192.0.2.55 - - [29/Oct/2026:10:03:03 +0530] "GET /.env HTTP/1.1" 404 162 "-" "curl/8.5.0" 8:192.0.2.55 - - [29/Oct/2026:10:06:45 +0530] "GET /admin HTTP/1.1" 404 162 "-" "curl/8.5.0"
Anchoring with ^ and escaping the dots makes sure only that exact address at the start of the line counts. Including the quote and spaces around the status code avoids matching 404 inside a byte count or a path.
Quick Quiz
1. Which command counts the lines containing "error", ignoring case?
-i ignores case and -c prints a count of matching lines.
2. What does grep -v "^#" sshd_config show?
^# matches lines starting with #, and -v inverts the match.
3. Which pattern needs grep -E (or backslashes) to work?
+ is an extended regex operator; ^ and $ work in basic mode too.
4. Which file names does grep -rl "8080" /etc/nginx print?
-r searches recursively and -l lists only the names of matching files.
Learn Linux with a mentor
Free lessons get you started. Our Ethical Hacking & Cyber Security training adds real projects and code reviews from working developers.
- Project-based learning
- Mentor code reviews
- Free counselling call
