Text Processing
Regular Expressions
Section titled “Regular Expressions”Regular expressions are the backbone of text processing on Linux. Three major flavors exist, each With different capabilities and syntax.
BRE vs ERE vs PCRE
Section titled “BRE vs ERE vs PCRE”| Flavor | Engine | Activator | Metacharacters Require Escape | Lookaround | | ------ | --------------- | ------------------ | ----------------------------- | ---------- | --- | | BRE | POSIX grep | Default | +?{`` |() | No | | ERE | POSIX grep -E | grep -E``egrep | None | No | | PCRE | Perl-compatible | grep -P``ripgrep | None | Yes |
BRE: \{1,3\} \+ \? \(group\)ERE: {1,3} + ? (group)PCRE: {1,3} + ? (group) + lookaround + backreferences + named groupsCharacter Classes and Anchors
Section titled “Character Classes and Anchors”Character Classes: [abc] any of a, b, c [a-z] lowercase letters [^0-9] NOT a digit [[:alpha:]] POSIX class — any letter [[:digit:]] POSIX class — any digit [[:alnum:]] letters or digits [[:space:]] whitespace [[:upper:]] uppercase letters [[:lower:]] lowercase letters
Anchors: ^ start of line (or start of string in multiline mode) $ end of line \b word boundary \B non-word boundary \< start of word (GNU extension) \> end of word (GNU extension)Quantifiers
Section titled “Quantifiers”Greedy (match as much as possible): * zero or more + one or more ? zero or one {n} exactly n {n,} n or more {n,m} between n and m
Lazy (match as little as possible — PCRE only): *? zero or more (lazy) +? one or more (lazy) ?? zero or one (lazy)Lookahead and Lookbehind (PCRE)
Section titled “Lookahead and Lookbehind (PCRE)”# Positive lookahead — match "foo" only when followed by "bar"grep -P "foo(?=bar)' file.txt
# Negative lookahead — match "foo" only when NOT followed by "bar"grep -P 'foo(?!bar)' file.txt
# Positive lookbehind — match "bar" only when preceded by "foo"grep -P '(?<=foo)bar' file.txt
# Negative lookbehind — match "bar" only when NOT preceded by "foo"grep -P '(?<!foo)bar' file.txtPractical Regex Patterns
Section titled “Practical Regex Patterns”# IPv4 addressgrep -P '(\d{1,3}\.){3}\d{1,3}' file.txt
# Email address (basic)grep -P '[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}' file.txt
# MAC addressgrep -P '([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}' file.txt
# UUIDgrep -P '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}' file.txt
# ISO 8601 dategrep -P '\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:?\d{2})?)?' file.txt
# Semantic versiongrep -P '\bv[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?(\+[a-zA-Z0-9.]+)?\b' file.txtsed — Stream Editor
Section titled “sed — Stream Editor”sed reads input line by line, applies editing commands, and writes output. It operates on a pattern space (a working buffer holding the current line) and a hold space (a secondary Buffer for multi-line operations).
Basic Substitution
Section titled “Basic Substitution”# Replace first occurrence per linesed 's/old/new/' file.txt
# Replace all occurrences per linesed 's/old/new/g' file.txt
# Replace on lines matching a patternsed '/error/s/warning/ERROR/g' file.txt
# Replace on specific line numberssed '3s/foo/bar/' file.txt
# Replace from line 3 to 5sed '3,5s/foo/bar/' file.txt
# Replace from line 3 to endsed '3,$s/foo/bar/' file.txtAddress Ranges
Section titled “Address Ranges”# Line numberssed -n '10,20p' file.txt # print lines 10-20sed '1d' file.txt # delete first linesed '$d' file.txt # delete last line
# Pattern rangessed '/start/,/end/d' file.txt # delete block between markerssed '/ERROR/,+3d' file.txt # delete ERROR line and 3 following lines
# Step rangessed '1~2d' file.txt # delete every 2nd line (odd lines)sed '0~3d' file.txt # delete every 3rd line (lines 3, 6, 9...)
# Regex with flagssed -n '/^#.*enabled/Ip' config # case-insensitive, print matchingHold Space Operations
Section titled “Hold Space Operations”The hold space is a secondary buffer. It persists across lines, enabling multi-line transformations.
# Copy pattern space to hold space (h), append (H)# Get hold space to pattern space (g), append (G)# Exchange pattern and hold space (x)
# Reverse the order of lines in a filesed '1!G;h;$!d' file.txt
# Join every two lines into onesed 'N;s/\n/ /' file.txt
# Delete blank lines and join previous line with nextsed '/^$/N;/\n$/d' file.txt
# Double-space a filesed G file.txt
# Print the line AFTER a pattern matchsed -n '/pattern/{n;p}' file.txtBranching and Flow Control
Section titled “Branching and Flow Control”# Label and branchsed '/start/b skip; s/foo/bar/; :skip' file.txt
# Conditional branch — skip substitution on comment linessed '/^#/b; s/enabled/disabled/' config
# Loop with t (branch if substitution was made)# Remove all leading spaces (not tabs) — one at a timesed ':loop; s/^ //; t loop' file.txt
# Infinite loop with breaksed ':top; s/ / /; t top' file.txt # collapse multiple spaces to onesed Scripts
Section titled “sed Scripts”For complex operations, use a sed script file:
cat > edit.sed << 'EOF'# Comment lines are ignored by sed/^#/ds/TODO/FIXME/g1,10s/enabled/disabled//^Listen /s/80/8080/$ a \# End of processed fileEOF
sed -f edit.sed httpd.confIn-Place Editing
Section titled “In-Place Editing”# Create backup with .bak extensionsed -i.bak 's/old/new/g' file.txt
# In-place without backup (dangerous — no recovery)sed -i 's/old/new/g' file.txt
# Operate on multiple filessed -i 's/192.168.1.100/10.0.0.1/g' /etc/hosts /etc/resolv.confPrefer cut when you only need simple field extraction — it is significantly faster than awk for Large files. Use awk when you need conditional logic, field manipulation, or aggregation.
paste and join
Section titled “paste and join”paste — Merge Lines
Section titled “paste — Merge Lines”# Merge two files side by side (tab-separated)paste file1.txt file2.txt
# Merge with a different delimiterpaste -d',' file1.txt file2.txt
# Paste files sequentially (not side by side)paste -s file.txt # all lines on one line
# Paste multiple filespaste file1.txt file2.txt file3.txtjoin — Relational Join
Section titled “join — Relational Join”# Inner join on first field (files must be sorted)join file1.txt file2.txt
# Join on specific fieldsjoin -1 2 -2 1 file1.txt file2.txt # field 2 of file1, field 1 of file2
# Unpaired linesjoin -a 1 file1.txt file2.txt # show unpaired from file1 (left join)join -a 2 file1.txt file2.txt # show unpaired from file2 (right join)join -a 1 -a 2 file1.txt file2.txt # full outer join
# Auto-fill empty fieldsjoin -e 'N/A' file1.txt file2.txt
# Specify output formatjoin -o '1.1 2.2' file1.txt file2.txttr — Character Translation
Section titled “tr — Character Translation”# Translate charactersecho 'hello' | tr 'a-z' 'A-Z' # HELLOecho 'Hello World' | tr '[:lower:]' '[:upper:]'
# Delete charactersecho 'hello 123' | tr -d '0-9' # helloecho 'hello' | tr -d 'l' # heo
# Complement and deleteecho 'hello123' | tr -d -c 'a-z' # hello (delete everything except a-z)
# Squeeze repeatsecho 'heeello' | tr -s 'l' # heelo
# Translate to single character (all spaces to newlines)echo 'one two three' | tr ' ' '\n'
# Convert DOS line endings to Unixtr -d '\r' < file.txt > file_unix.txt
# Remove non-printable characterstr -cd '[:print:]\n' < file.txt
# ROT13echo 'secret' | tr 'a-zA-Z' 'n-za-mN-ZA-M'Common Pitfalls
Section titled “Common Pitfalls”Pitfall: BRE Escaping in sed
Section titled “Pitfall: BRE Escaping in sed”# WRONG — BRE requires escaping quantifierssed 's/[0-9]+/NUMBER/g' file.txt # matches "[0-9]" followed by literal "+"
# CORRECT — escape the quantifier in BREsed 's/[0-9]\+/NUMBER/g' file.txt # matches one or more digits
# ALTERNATIVE — use ERE with -E flagsed -E 's/[0-9]+/NUMBER/g' file.txt # matches one or more digitsPitfall: awk Floating-Point Precision
Section titled “Pitfall: awk Floating-Point Precision”# awk uses double-precision floating point — expect rounding errorsawk 'BEGIN {print 0.1 + 0.2}' # outputs 0.3 (display rounding)awk 'BEGIN {printf "%.20f\n", 0.1 + 0.2}' # outputs 0.30000000000000004441
# For financial data, use integer arithmetic (cents)awk '{printf "%d.%02d\n", $1/100, $1%100}' transactions.txtPitfall: grep Returning Non-Zero on No Match
Section titled “Pitfall: grep Returning Non-Zero on No Match”# grep exits with 1 when no lines match — this breaks set -e scriptsset -egrep "pattern" file.txt # script exits if no match!
# Fix: use || truegrep "pattern" file.txt || true
# Fix: use --quiet with a testif grep -q "pattern" file.txt; then echo "found"fiPitfall: jq on Huge Files
Section titled “Pitfall: jq on Huge Files”# jq loads the entire JSON into memoryjq '.' huge.json # may OOM on multi-gigabyte files
# For large files, use streaming modejq -c '.[]' huge.json | while read -r obj; do echo "$obj" | jq '.id'done
# Or use jq's --stream flag for very large filesjq --stream 'fromstream(1|truncate_stream(inputs))' huge.jsonPitfall: sed with Paths Containing Delimiters
Section titled “Pitfall: sed with Paths Containing Delimiters”# WRONG — slashes in the path break the sed commandsed 's|/old/path|/new/path|g' file.txt # works if using | as delimiter
# CORRECT — use a different delimitersed 's|/old/path|/new/path|g' file.txt
# CORRECT — escape the delimitersed 's/\/old\/path/\/new\/path/g' file.txt
# Use | or # or @ as delimiter when paths contain /sed 's#/var/log#/opt/log#g' configPitfall: sort Locale Sensitivity
Section titled “Pitfall: sort Locale Sensitivity”# Default sort uses locale — order may be unexpectedsort file.txt # 'A' may sort after 'z' depending on locale
# Fix: use C locale for byte-order sortingLC_ALL=C sort file.txt
# Fix: set LC_ALL=C for the duration of a pipelineexport LC_ALL=C; sort file.txt | uniqPitfall: cut Does Not Handle Multi-Character Delimiters
Section titled “Pitfall: cut Does Not Handle Multi-Character Delimiters”# cut only accepts single-character delimiterscut -d'|' file.txt # works — single charactercut -d'||' file.txt # WRONG — uses only the first '|'
# Fix: use awk insteadawk -F'\\|\\|' '{print $1, $2}' file.txtPitfall: In-Place sed on Files with No Write Permission
Section titled “Pitfall: In-Place sed on Files with No Write Permission”# sed -i creates a temporary file, then renames it# If the target directory is read-only, this fails silently or partiallysed -i 's/old/new/g' /readonly/file.txt # may fail
# Fix: write to a temp directorysed "s/old/new/g" /readonly/file.txt > /tmp/file.txt && sudo cp /tmp/file.txt /readonly/file.txtSummary
Section titled “Summary”This topic covers the core concepts of text processing, including underlying theory, practical implementation, and key applications.
Key concepts include:
- variables, data types, and control flow
- functions and procedures
- object-oriented programming
- error handling and debugging
- modular design
Understanding these concepts thoroughly is essential for both examinations and practical programming, and requires both theoretical knowledge and hands-on practice.
Worked Examples
Section titled “Worked Examples”Worked examples demonstrating the application of key concepts are covered in the detailed sub-pages linked above.