Home DevOps Grep, Awk, and Sed: Text Processing Power Tools for Production Logs
Intermediate 3 min · July 18, 2026

Grep, Awk, and Sed: Text Processing Power Tools for Production Logs

Master grep, awk, and sed for production log analysis.

N
Naren Founder & Principal Engineer

20+ years shipping production infrastructure and CI/CD at scale. Drawn from code that ran under real load.

Follow
Production
production tested
July 18, 2026
last updated
2,466
articles · all by Naren
Before you start⏱ 30 min
  • Basic Linux command line
  • Familiarity with regular expressions
  • Understanding of standard streams (stdin, stdout, stderr)
 ● Production Incident 🔎 Debug Guide ⚙ Triage Commands
Quick Answer

Use grep to find lines matching a pattern, awk to extract and reformat columns, and sed to substitute text. Chain them with pipes: grep 'ERROR' app.log | awk '{print $1, $5}' | sed 's/ERROR/CRITICAL/g'.

✦ Definition~90s read
What is Grep, Awk, and Sed?

Grep, awk, and sed are Unix command-line tools for searching, filtering, and transforming text. Grep finds lines matching patterns, awk processes structured columns, and sed edits streams. Together they form a text processing pipeline that handles log analysis, config parsing, and data extraction without writing scripts.

Imagine you're a detective with a stack of papers.
Plain-English First

Imagine you're a detective with a stack of papers. Grep is a highlighter that marks every line containing a suspect's name. Awk is a pair of scissors that cuts out specific columns from a table. Sed is a white-out pen that corrects typos across the whole stack. Together, you can highlight, cut, and correct without ever touching a paper.

You're tailing a 2GB production log at 3 AM. The payment service is throwing 500s. You need to find every occurrence of 'TransactionTimeout' in the last hour, extract the order IDs and timestamps, and replace the error code with a more descriptive message. You have 30 seconds before the on-call phone rings again. This is where grep, awk, and sed save your night.

These three tools are the Unix text processing trinity. They're not just for sysadmins—every developer who touches a server needs them. Without them, you're grepping in an IDE that can't handle 2GB files, or writing a Python script that takes 10 minutes to import pandas. With them, you solve the problem in one line.

By the end of this article, you'll be able to build complex text pipelines from memory. You'll know when to use each tool, how to combine them, and—more importantly—when not to. You'll stop fearing raw logs and start treating them like a structured database you query with pipes.

Grep: The Laser-Focused Searcher

Grep is your first line of defense. It finds lines matching a pattern. But most people only use grep 'pattern' file. That's like using a chainsaw to cut butter. Let's talk about the flags that matter.

-i for case-insensitive search. -v to invert match—show everything that doesn't match. -c to count matches. -n to show line numbers. -r for recursive search through directories. -l to list only filenames with matches.

In production, you'll often combine these. Need to find all lines that don't contain 'INFO' in a directory of logs? grep -rv 'INFO' /var/log/. Want to count how many times each error appears? grep -o 'ERROR.*' app.log | sort | uniq -c.

But here's the trap: grep reads the entire file. For a 10GB log, that's slow. Always pipe from tail or head first if you only need recent lines. tail -n 10000 app.log | grep 'CRITICAL' is your friend.

grep_production.shBASH
1
2
3
4
5
6
7
8
9
10
// io.thecodeforge — DevOps tutorial

# Find all CRITICAL errors in the last 10,000 lines of the payment log
tail -n 10000 /var/log/payment.log | grep -i 'CRITICAL' > /tmp/critical_errors.txt

# Count occurrences of each error type in the whole log
grep -o 'ERROR: [A-Za-z]*' /var/log/payment.log | sort | uniq -c | sort -rn

# Recursively find all files containing 'OutOfMemory' in /var/log
grep -rl 'OutOfMemory' /var/log/
Output
150 ERROR: Timeout
45 ERROR: ConnectionRefused
12 ERROR: OutOfMemory
/var/log/app1.log
/var/log/app2.log
⚠ Production Trap: Grep Without Context
Running grep 'ERROR' huge.log on a 10GB file can take minutes and spike CPU to 100%. Always limit input with tail or head first. Or use grep --line-buffered when piping to another command to avoid waiting for full output.

Awk: The Column Whisperer

Grep finds lines. Awk processes them. It's a full programming language disguised as a command. At its core, awk splits each line into fields ($1, $2, etc.) and lets you print, filter, or compute.

Default field separator is whitespace. Use -F to change it. awk '{print $1, $3}' prints the first and third columns. awk '$2 > 100' prints lines where the second field is greater than 100. awk 'NR==10' prints line 10.

In production, awk shines for log analysis. Log lines often have timestamps, levels, and messages. awk '{print $1, $2, $5}' extracts date, time, and error code. awk -F'[][]' '{print $2}' splits on brackets—useful for Apache logs.

But awk has a learning curve. Start with simple field extraction. Add conditions gradually. And remember: awk processes line by line—it's memory efficient even on huge files.

awk_production.shBASH
1
2
3
4
5
6
7
8
9
10
11
// io.thecodeforge — DevOps tutorial

# Extract timestamp and response time from an Apache access log
# Log format: 127.0.0.1 - frank [10/Oct/2000:13:55:36 -0700] "GET /apache_pb.gif HTTP/1.0" 200 2326
awk '{print $4, $5, $10}' /var/log/apache/access.log | head -5

# Filter lines where response time (field 10) > 5000 (5 seconds)
awk '$10 > 5000 {print $4, $5, $10}' /var/log/apache/access.log

# Sum total bytes sent (field 10) per IP (field 1)
awk '{bytes[$1] += $10} END {for (ip in bytes) print ip, bytes[ip]}' /var/log/apache/access.log | sort -k2 -rn | head -10
Output
[10/Oct/2000:13:55:36 -0700] 200 2326
[10/Oct/2000:13:55:36 -0700] 200 1043
...
192.168.1.1 104857600
10.0.0.2 52428800
💡Senior Shortcut: Awk One-Liners for Logs
Use awk '!seen[$0]++' to remove duplicate lines. Use awk 'NR%2==0' to print even lines. Use awk '{for(i=1;i<=NF;i++) if($i ~ /error/) print NR, $i}' to find which field contains 'error'.

Sed: The Stream Editor That Never Forgets

Sed is for editing text in a pipeline. The most common use is substitution: sed 's/old/new/g'. But sed can also delete lines, insert text, and apply multiple edits.

-i edits the file in place (use with caution—backup first). -n suppresses automatic printing, used with p to print only matching lines. d deletes lines. a appends after a line. i inserts before.

In production, sed is perfect for config file changes. Need to update a database connection string across 50 servers? sed -i 's/old_host/new_host/g' /etc/app/config.properties. Need to remove all comment lines? sed -i '/^#/d' config.

But sed's syntax is terse. Use extended regex with -E for readability. And always test without -i first: sed 's/pattern/replacement/' file prints to stdout—verify before committing.

sed_production.shBASH
1
2
3
4
5
6
7
8
9
10
11
12
13
// io.thecodeforge — DevOps tutorial

# Replace all occurrences of 'localhost' with 'db-prod-1' in config
sed -i 's/localhost/db-prod-1/g' /etc/app/database.properties

# Delete all lines containing 'DEBUG' from a log (for cleanup)
sed -i '/DEBUG/d' /var/log/app.log

# Print lines 100 to 200 from a file
sed -n '100,200p' /var/log/app.log

# Insert a new line after line 5
sed '5a\new_config_entry=true' config.properties
Output
# (no output for in-place edits; for print: lines 100-200 of the file)
⚠ Never Do This: Sed -i Without Backup
sed -i 's/foo/bar/g' important.conf overwrites the file. If your regex is wrong, you corrupt the config. Always use -i.bak to create a backup: sed -i.bak 's/foo/bar/g' important.conf.

Combining Grep, Awk, and Sed: The Pipeline

The real power comes from chaining them. Each tool does one thing well: grep filters lines, awk processes fields, sed edits. Pipe them together to build a processing pipeline.

Classic pattern: grep 'ERROR' log | awk '{print $1, $5}' | sed 's/ERROR/CRITICAL/g'. This finds errors, extracts timestamp and error code, then renames the level.

Another pattern: tail -f log | grep --line-buffered 'ERROR' | awk '{print $1}'. Real-time monitoring of error timestamps.

But beware: each pipe creates a subprocess. For huge files, this can be slow. If you need complex logic, consider a small Python script instead. But for 90% of log analysis, the pipeline is faster to write and run.

pipeline_production.shBASH
1
2
3
4
5
6
7
// io.thecodeforge — DevOps tutorial

# Extract all 5xx errors from nginx access log, get IP and URI, replace status with 'SERVER_ERROR'
tail -n 50000 /var/log/nginx/access.log | grep ' "5[0-9][0-9] ' | awk '{print $1, $7, $9}' | sed 's/5[0-9][0-9]/SERVER_ERROR/g' > /tmp/5xx_errors.txt

# Count unique IPs that caused 5xx errors
tail -n 50000 /var/log/nginx/access.log | grep ' "5[0-9][0-9] ' | awk '{print $1}' | sort | uniq -c | sort -rn | head -10
Output
192.168.1.100 /api/checkout SERVER_ERROR
10.0.0.5 /api/payment SERVER_ERROR
...
500 192.168.1.100
200 10.0.0.5
🔥Interview Gold: Pipeline Performance
Each pipe buffers output. For real-time streaming, use grep --line-buffered and awk '{print; fflush()}' to force flush. Without buffering, you might wait minutes for output.

When Not to Use These Tools

Grep, awk, and sed are not always the answer. For structured data like JSON or XML, they're fragile. A JSON value with spaces breaks awk's field splitting. A nested XML tag confuses sed.

Use jq for JSON. Use xpath or xmlstarlet for XML. Use Python or Perl for complex multi-line patterns.

Also, for files larger than RAM, these tools still work (they stream), but if you need random access or joins, consider a database or Spark.

Finally, if your pipeline has more than 5 pipes, write a script. It'll be more readable and maintainable.

when_not_to.shBASH
1
2
3
4
5
6
7
// io.thecodeforge — DevOps tutorial

# Bad: parsing JSON with awk (breaks if values contain spaces)
# echo '{"name": "John Doe"}' | awk -F'"' '{print $4}'

# Good: use jq
echo '{"name": "John Doe"}' | jq -r '.name'
Output
John Doe
💡Senior Shortcut: Know Your Tools
For CSV, use csvkit or awk -F',' if simple. For log files with consistent format, these tools are unbeatable. For anything else, reach for a purpose-built parser.
● Production incidentPOST-MORTEMseverity: high

The 4GB Log That Broke My Editor

Symptom
Payment service returning 503 errors. No obvious pattern in the last 100 lines of the log.
Assumption
Thought it was a database connection pool issue. Restarted the service twice—no change.
Root cause
A misconfigured thread pool was exhausting connections, but the error log was buried in 4GB of debug output. grep 'ERROR' found 12,000 lines—too many to read manually. Needed to filter by timestamp and error type.
Fix
Used grep '2025-03-15 14:' app.log | grep 'ThreadPoolExhausted' | awk '{print $1, $2, $6}' to isolate the exact minute and thread count. Found the pool size was 10—bumped to 50. Problem solved in 15 seconds.
Key lesson
  • When logs are huge, don't grep the whole file—pipe through multiple greps to narrow down.
  • And always know your thread pool limits.
Production debug guideSystematic recovery paths for the failure modes engineers actually hit.3 entries
Symptom · 01
grep returns no results but you know the pattern exists
Fix
1. Check case sensitivity: add -i. 2. Check if file is binary: use grep -a. 3. Check if pattern has special characters: escape them or use -F for fixed strings.
Symptom · 02
awk prints wrong columns or nothing
Fix
1. Check field separator: use -F' ' explicitly. 2. Print all fields with {print $0} to see the line. 3. Check if fields are empty: use $1 != "" condition.
Symptom · 03
sed substitution doesn't work
Fix
1. Test without -i first. 2. Use -E for extended regex. 3. Check if pattern contains /: use different delimiter like s|old|new|.
★ Grep, Awk, and Sed Triage Cheat SheetFirst-response commands for when things go wrong — copy-paste ready.
grep returns no results but pattern exists
Immediate action
Check case and special characters
Commands
grep -i 'pattern' file
grep -a 'pattern' file
Fix now
Use -i for case-insensitive, -F for fixed string
awk prints empty lines+
Immediate action
Check field separator
Commands
awk '{print NF, $0}' file
awk -F',' '{print $1}' file
Fix now
Set correct -F flag
sed doesn't change file+
Immediate action
Check if `-i` is missing
Commands
sed 's/old/new/' file
sed -i 's/old/new/' file
Fix now
Add -i for in-place edit
Pipeline too slow+
Immediate action
Check buffering
Commands
grep --line-buffered 'pattern' file | awk '{print; fflush()}'
stdbuf -oL grep 'pattern' file
Fix now
Use --line-buffered or stdbuf
FeatureGrepAwkSed
Primary useSearch lines by patternProcess columns/fieldsEdit text in place
Performance on large filesFast (single pass)Fast (single pass)Fast (single pass)
Learning curveLowMediumMedium
Built-in programmingNoYes (variables, loops)Limited (branching)
Best forFiltering log linesExtracting metricsConfig file changes
⚙ Quick Reference
5 commands from this guide
FileCommand / CodePurpose
grep_production.shtail -n 10000 /var/log/payment.log | grep -i 'CRITICAL' > /tmp/critical_errors.t...Grep
awk_production.shawk '{print $4, $5, $10}' /var/log/apache/access.log | head -5Awk
sed_production.shsed -i 's/localhost/db-prod-1/g' /etc/app/database.propertiesSed
pipeline_production.shtail -n 50000 /var/log/nginx/access.log | grep ' "5[0-9][0-9] ' | awk '{print $1...Combining Grep, Awk, and Sed
when_not_to.shecho '{"name": "John Doe"}' | jq -r '.name'When Not to Use These Tools

Key takeaways

1
Grep finds lines, awk processes columns, sed edits text—use each for its strength.
2
Always limit input with tail or head before grepping huge files to avoid CPU spikes.
3
Test sed substitutions without -i first, and always use -i.bak for backups.
4
For JSON or XML, don't use these tools—use dedicated parsers like jq or xmlstarlet.
INTERVIEW PREP · PRACTICE MODE

Interview Questions on This Topic

Q01SENIOR
How does grep handle binary files? What flag forces text mode?
Q02SENIOR
When would you choose awk over a Python script for log processing?
Q03SENIOR
What happens when sed runs out of memory on a huge file? How do you miti...
Q04JUNIOR
What does `grep -c` count? How is it different from `wc -l`?
Q05SENIOR
You need to extract the 3rd column from a CSV where some fields are quot...
Q06SENIOR
How would you design a real-time log monitoring pipeline using these too...
Q01 of 06SENIOR

How does grep handle binary files? What flag forces text mode?

ANSWER
Grep by default checks if a file is binary and skips it. Use -a to treat binary as text. This is critical when grepping through mixed log files that contain null bytes.
FAQ · 4 QUESTIONS

Frequently Asked Questions

01
What is the difference between grep, awk, and sed?
02
Can I use grep, awk, and sed on Windows?
03
How do I replace a string in multiple files with sed?
04
How do I extract the last column from a log line with awk?
N
Naren Founder & Principal Engineer

20+ years shipping production infrastructure and CI/CD at scale. Drawn from code that ran under real load.

Follow
Verified
production tested
July 18, 2026
last updated
2,466
articles · all by Naren
🔥

That's Linux. Mark it forged?

3 min read · try the examples if you haven't

Previous
Bash Scripting: Variables, Loops, and Functions
14 / 16 · Linux
Next
iptables: Linux Firewall Configuration and Management