Skip to content

Text Processing | Linux - Wyatt's Notes

Regular expressions are the backbone of text processing on Linux. Three major flavors exist, each With different capabilities and syntax.

| 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 groups
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)
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)
Terminal window
## 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.txt
Terminal window
# IPv4 address
grep -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 address
grep -P '([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}' file.txt
# UUID
grep -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 date
grep -P '\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:?\d{2})?)?' file.txt
# Semantic version
grep -P '\bv[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?(\+[a-zA-Z0-9.]+)?\b' file.txt

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).

Terminal window
# Replace first occurrence per line
sed 's/old/new/' file.txt
# Replace all occurrences per line
sed 's/old/new/g' file.txt
# Replace on lines matching a pattern
sed '/error/s/warning/ERROR/g' file.txt
# Replace on specific line numbers
sed '3s/foo/bar/' file.txt
# Replace from line 3 to 5
sed '3,5s/foo/bar/' file.txt
# Replace from line 3 to end
sed '3,$s/foo/bar/' file.txt
Terminal window
# Line numbers
sed -n '10,20p' file.txt # print lines 10-20
sed '1d' file.txt # delete first line
sed '$d' file.txt # delete last line
# Pattern ranges
sed '/start/,/end/d' file.txt # delete block between markers
sed '/ERROR/,+3d' file.txt # delete ERROR line and 3 following lines
# Step ranges
sed '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 flags
sed -n '/^#.*enabled/Ip' config # case-insensitive, print matching

The hold space is a secondary buffer. It persists across lines, enabling multi-line transformations.

Terminal window
# 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 file
sed '1!G;h;$!d' file.txt
# Join every two lines into one
sed 'N;s/\n/ /' file.txt
# Delete blank lines and join previous line with next
sed '/^$/N;/\n$/d' file.txt
# Double-space a file
sed G file.txt
# Print the line AFTER a pattern match
sed -n '/pattern/{n;p}' file.txt
Terminal window
# Label and branch
sed '/start/b skip; s/foo/bar/; :skip' file.txt
# Conditional branch — skip substitution on comment lines
sed '/^#/b; s/enabled/disabled/' config
# Loop with t (branch if substitution was made)
# Remove all leading spaces (not tabs) — one at a time
sed ':loop; s/^ //; t loop' file.txt
# Infinite loop with break
sed ':top; s/ / /; t top' file.txt # collapse multiple spaces to one

For complex operations, use a sed script file:

Terminal window
cat > edit.sed << 'EOF'
# Comment lines are ignored by sed
/^#/d
s/TODO/FIXME/g
1,10s/enabled/disabled/
/^Listen /s/80/8080/
$ a \
# End of processed file
EOF
sed -f edit.sed httpd.conf
Terminal window
# Create backup with .bak extension
sed -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 files
sed -i 's/192.168.1.100/10.0.0.1/g' /etc/hosts /etc/resolv.conf