Stage 3 · Build
Shell Scripting & Automation
awk, sed & grep
Field extraction, regex filtering, stream editing, and safe log slicing with awk, sed, and grep.
grep Pattern Matching
# Basic pattern matching
grep "error" /var/log/syslog
# Case-insensitive
grep -i "error" logfile
# Invert match (exclude)
grep -v "debug" logfile
# Recursive search
grep -r "TODO" src/
# Count matches
grep -c "error" logfile
# Show line numbers
grep -n "error" logfile
# Extended regex (egrep)
grep -E "error|warning|critical" logfile
# Perl regex (for complex patterns)
grep -P "\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}" logfile
# Show context (3 lines before/after)
grep -B3 -A3 "error" logfile
# Only match the pattern, not the whole line
grep -o "error:.*" logfile | head -5grep searches for patterns in text. -E for extended regex, -P for Perl regex. Always use -i for case-insensitive search.
awk Essentials
# Print specific fields
awk '{print $1, $3}' /etc/passwd
# root:x /root
# daemon:x /usr/sbin
# Print last field
awk '{print $NF}' /etc/passwd
# Custom delimiter
awk -F: '{print $1, $6}' /etc/passwd
# root /root
# daemon /usr/sbin
# Print lines matching a pattern
awk '/error/ {print $0}' logfile
# Print fields where condition is met
awk '$3 > 100 {print $1, $3}' data.txt
# Field count
awk '{print NR, NF, $0}' file | head -5
# 1 7 root:x:0:0:root:/root:/bin/bash
# Line number, field count, full lineawk processes text line by line. $0 is the full line, $1 is the first field, $NF is the last field. -F sets the field separator.
# BEGIN/END blocks
awk 'BEGIN{sum=0} {sum+=$3} END{print "Total:", sum}' data.txt
# Associative arrays
awk '{count[$1]++} END{for(k in count) print k, count[k]}' access.log
# Conditional logic
awk -F: '{
if ($3 >= 1000)
printf "%-20s UID=%s\n", $1, $3
}' /etc/passwd
# Calculate average
awk '{sum+=$1; count++} END{print "Average:", sum/count}' numbers.txt
# Remove duplicates
awk '!seen[$0]++' file.txt
# Output to variable
result=$(awk -F: '$3 == 0 {print $1}' /etc/passwd)
echo "Root user: $result"awk is a full programming language. Use BEGIN/END for initialization/finalization. Associative arrays enable counting and grouping.
sed Stream Editing
# Basic substitution
sed 's/old/new/' file.txt # First occurrence per line
sed 's/old/new/g' file.txt # All occurrences per line
sed -i 's/old/new/g' file.txt # In-place editing
# Case-insensitive substitution
sed 's/error/warning/gI' logfile
# Delete lines
sed '/pattern/d' file.txt # Delete matching lines
sed '3d' file.txt # Delete line 3
sed '1,5d' file.txt # Delete lines 1-5
# Print specific lines
sed -n '5,10p' file.txt # Print lines 5-10
sed -n '/start/,/end/p' file.txt # Print between patterns
# Insert/append
sed '3i\new line here' file.txt # Insert before line 3
sed '3a\new line here' file.txt # Append after line 3
# Multiple commands
sed -e 's/foo/bar/g' -e 's/baz/qux/g' file.txt
sed '/pattern/{s/old/new/g; s/foo/bar/g}' file.txtsed edits streams line by line. s/// is substitution, /d is deletion, /p is printing. -i edits files in-place.
Combining Tools
# Find top 10 IP addresses in access log
awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -10
# Count errors by hour
grep "error" logfile | awk '{print $4}' | cut -d: -f1 | sort | uniq -c
# Extract and sort unique URLs
awk '{print $7}' access.log | sort -u > urls.txt
# Find large files
find / -type f -exec ls -la {} \; | awk '$5 > 1000000 {print $5, $9}'
# Parse docker logs
docker logs container 2>&1 | grep -v "health" | awk '/error/{print $0}'
# Log analysis pipeline
cat access.log | \
awk '$9 >= 500 {print $0}' | \
sed 's/\[".*"\]/\"\"\"/' | \
sort | uniq -c | sort -rnThe power of Unix is in combining simple tools. grep filters, awk extracts, sort orders, uniq counts, head truncates.
Safe Log Slicing
# Extract logs from a specific time range
awk '/2024-01-15 10:00/,/2024-01-15 12:00/' logfile
# Extract today's logs
awk '/$(date +%Y-%m-%d)/' logfile
# Extract logs from last hour
awk -v hour="$(date -d '1 hour ago' +%H)" '$4 ~ hour' logfile
# Safe log rotation (atomic)
mv logfile logfile.$(date +%Y%m%d%H%M%S)
kill -HUP $(cat /var/run/syslog.pid)
# Extract between timestamps (ISO format)
awk '/2024-01-15T10:00/,/2024-01-15T12:00/' logfileawk is excellent for time-based log slicing. Use the timestamp format that matches your log format for reliable extraction.
Performance Tips
- Use grep for simple pattern matching (faster than awk/sed)
- Use awk for field extraction and text processing
- Use sed for simple substitutions on streams
- Use ripgrep (rg) instead of grep for large codebases
- Combine tools in pipelines rather than writing complex awk one-liners
- Use -F for custom delimiters instead of parsing with regex
ripgrep (rg) is 10x faster than grep for code searching. It respects .gitignore, uses parallel processing, and has better Unicode support.
sed -i modifies files directly. Always test without -i first. Use sed -i.bak to create a backup before editing.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.