Shell Scripting SED Advanced SED Advanced May 2026

Shell Scripting Advanced SED: Fundamentals

Master SED's execution model, the pattern space, all primary commands (s, d, p, q, a, i, c, y), address forms, in-place editing, and the key differences between GNU sed and BSD sed that break scripts across platforms.

SED (Stream Editor) is the specialist tool for text substitution and transformation in shell pipelines. While AWK is a programming language that happens to process text, SED is a pure transformation engine — it applies a script of commands to each line of input and outputs the result. Understanding SED deeply makes you faster at config file editing, log transformation, and in-place file updates.

BASH
# SED cycle (repeated for each input line):
# 1. Read line into pattern space
# 2. Apply commands in sequence to pattern space
# 3. Print pattern space (unless -n)
# 4. Clear pattern space and go to next line

# ── Basic invocation ──────────────────────────────────────
sed 'COMMAND' file.txt          # apply to file
echo "text" | sed 'COMMAND'     # apply to stdin
sed -n 'COMMAND' file.txt       # -n: suppress auto-print
sed -i 'COMMAND' file.txt       # -i: edit file in place (GNU sed)
sed -i.bak 'COMMAND' file.txt   # -i.bak: in-place with backup
sed -E 'COMMAND' file.txt       # -E: extended regex (no backslash)

# ── Multiple commands ─────────────────────────────────────
sed '/ERROR/d; s/WARN/WARNING/' file.txt   # semicolon separator
sed -e '/ERROR/d' -e 's/WARN/WARNING/'   # multiple -e flags
sed '
/ERROR/d
s/WARN/WARNING/
' file.txt                                 # multiline string

# ── GNU sed vs BSD sed (macOS) ─────────────────────────────
# GNU sed: sed -i 's/old/new/' file        (no space needed)
# BSD sed: sed -i '' 's/old/new/' file     (empty string required)
# Safe cross-platform in-place edit:
if [[ "$(uname)" == "Darwin" ]]; then
  sed -i '' 's/old/new/g' file.txt
else
  sed -i 's/old/new/g' file.txt
fi
SED
# ── s — substitute (most used) ────────────────────────────
sed 's/old/new/'        # replace first occurrence per line
sed 's/old/new/g'       # replace all occurrences (global)
sed 's/old/new/2'       # replace second occurrence only
sed 's/old/new/i'       # case-insensitive (GNU sed)
sed 's/old/new/gp'      # replace all + print if changed

# ── d — delete line ────────────────────────────────────────
sed '/pattern/d'        # delete lines matching pattern
sed '/^#/d'             # delete comment lines
sed '/^[[:space:]]*$/d' # delete blank lines
sed '1d'                # delete first line
sed '$d'                # delete last line
sed '2,5d'              # delete lines 2 through 5

# ── p — print ─────────────────────────────────────────────
sed -n '/ERROR/p'       # print only lines matching ERROR
sed -n '5p'             # print only line 5
sed -n '5,10p'          # print lines 5-10
sed -n '$p'             # print last line

# ── q — quit ──────────────────────────────────────────────
sed '5q'                # print first 5 lines and quit (like head -5)
sed '/ERROR/q'          # print up to and including first ERROR

# ── a, i, c — append, insert, change ─────────────────────
sed '/pattern/a\Added after'    # append line after match
sed '/pattern/i\Added before'   # insert line before match
sed '/pattern/c\Replaced line'  # replace entire line

# ── y — transliterate ─────────────────────────────────────
sed 'y/abc/ABC/'         # a→A, b→B, c→C (like tr)
sed 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'  # uppercase
BASH
# SED address: [address] command
# Address specifies WHICH lines the command applies to

# ── Numeric addresses ─────────────────────────────────────
sed '1s/old/new/'        # only first line
sed '$s/old/new/'        # only last line
sed '2,5s/old/new/'      # lines 2 through 5
sed '2,~5s/old/new/'     # line 2 through next mult of 5 (GNU)
sed '0~2s/old/new/'      # every 2nd line starting at 0 (GNU)
sed '1~2s/old/new/'      # every odd line (GNU)

# ── Regex addresses ───────────────────────────────────────
sed '/ERROR/s/old/new/'  # only on ERROR lines
sed '/^#/d'              # delete comment lines

# ── Range addresses ───────────────────────────────────────
sed '/START/,/END/s/old/new/'   # between START and END
sed '/START/,/END/d'            # delete block between START and END
sed '1,/PATTERN/d'              # delete from line 1 to first PATTERN
sed '/PATTERN/,$d'              # delete from PATTERN to end of file

# ── Negated address (!) ────────────────────────────────────
sed '/ERROR/!d'          # delete lines NOT matching ERROR
sed '1!s/old/new/'       # substitute on all but first line
sed — fundamentals demo
vriddh@prod-01:~/scripts$echo "Hello World Error" | sed 's/Error/Fixed/'
Hello World Fixed
vriddh@prod-01:~/scripts$sed '/^#/d; /^[[:space:]]*$/d' config.conf | head -5
DB_HOST=prod-db-01
DB_PORT=3306
APP_ENV=production
vriddh@prod-01:~/scripts$sed -n '5,10p' app.log
[2026-05-01 10:14:05] INFO Service started
[2026-05-01 10:14:06] ERROR DB connection failed
⚠ GNU sed vs BSD sed (macOS) — The most common cross-platform breakage: sed -i 's/old/new/' file works on GNU/Linux but fails on macOS BSD sed. On macOS you need sed -i '' 's/old/new/' file. For scripts that must run on both, detect the platform or install GNU sed via Homebrew (brew install gnu-sed provides gsed).
✔ SED fundamentalss/pattern/replacement/flags is the core. Use g for global, I for case-insensitive (GNU). Use -n with p to print only matched lines. Use -i for in-place editing — always with .bak suffix until you trust the expression. Use -E for extended regex to avoid backslashing +, ?, (), and |.