/user/kayd @ devops :~$ cat bash-sed-awk.md

Bash sed & awk Cheatsheet Bash sed & awk Cheatsheet

QR Code linking to: Bash sed & awk Cheatsheet
Karandeep Singh
Karandeep Singh
• 6 minutes

Summary

My working reference for sed and awk. Substitution, addresses, capture groups, fields, BEGIN/END blocks, associative arrays, and the one-liners I actually use.

Half of DevOps is reshaping text: log files, CSVs, config files, command output. sed and awk are the two tools I reach for constantly, and somehow I still re-derive the syntax from scratch every time. So I wrote it down. If your shell fundamentals are rusty, start with the Bash Basics Cheatsheet first.

sed: Substitution

Docs: GNU sed manual

sed 's/foo/bar/' file            # replace first foo per line
sed 's/foo/bar/g' file           # replace ALL per line
sed 's/foo/bar/2' file           # only the 2nd occurrence per line
sed 's/foo/bar/gi' file          # global + case-insensitive
sed 's|/var/log|/mnt/log|g' file # any delimiter, handy for paths
sed -E 's/[0-9]+/N/g' file       # -E: extended regex (no backslash escaping)
sed -n 's/foo/bar/p' file        # print only lines where a change happened

sed: Deletion & Insertion

Docs: sed(1) man page

sed '/^#/d' config.conf          # delete comment lines
sed '/^$/d' file                 # delete blank lines
sed '3d' file                    # delete line 3
sed '2,5d' file                  # delete lines 2-5
sed '$d' file                    # delete last line

sed '3i\inserted before line 3' file
sed '3a\appended after line 3'  file
sed '/^\[nginx\]/a\worker_processes auto;' app.ini   # append after a match
sed '/pattern/c\replacement line' file               # change whole line

sed: In-Place Editing (GNU vs BSD Gotcha)

Docs: GNU sed manual

sed -i 's/foo/bar/g' file        # GNU sed (Linux): edit in place
sed -i.bak 's/foo/bar/g' file    # in place + keep file.bak backup

sed: Addresses & Ranges

Docs: GNU sed manual

AddressApplies command to…
5Line 5
$Last line
2,10Lines 2 through 10
/regex/Lines matching regex
/start/,/end/From a start match to the next end match
0~3Every 3rd line (GNU)
5,$Line 5 to end of file
/regex/!Lines NOT matching
sed -n '10,20p' file                    # print lines 10-20
sed -n '/BEGIN CERT/,/END CERT/p' pem   # extract a certificate block
sed '/^#/!s/foo/bar/' file              # substitute only on non-comments
sed '1,/^$/d' mail.txt                  # delete headers (up to first blank line)

sed: Capture Groups & Backreferences

Docs: GNU sed manual

sed -E 's/(user)-([0-9]+)/\2-\1/' file        # swap: user-42 -> 42-user
sed -E 's/^([a-z]+)=(.*)$/export \1="\2"/'    # key=val -> export key="val"
sed -E 's/(error)/[\1]/gi' app.log            # wrap matches; \1 refers back
sed -E 's/([0-9]{4})-([0-9]{2})-([0-9]{2})/\3\/\2\/\1/'  # date reshuffle
sed 's/.*"id": *"\([^"]*\)".*/\1/' resp.json  # basic regex needs \( \)

& in the replacement means “the whole match”: sed -E 's/[0-9]+/<&>/g'.

awk: Fields & Built-in Variables

Docs: GNU gawk manual

awk splits each line into fields: $1, $2, … $NF. $0 is the whole line.

VariableMeaning
NRCurrent line (record) number
NFNumber of fields on this line
FSInput field separator (default: runs of whitespace)
OFSOutput field separator (default: single space)
RS / ORSInput / output record separator
FILENAMECurrent input file
FNRLine number within the current file
awk '{print $1, $3}' access.log         # fields 1 and 3
awk '{print $NF}' file                  # last field
awk '{print $(NF-1)}' file              # second-to-last
awk -F: '{print $1}' /etc/passwd        # -F sets FS: usernames
awk -F',' -v OFS='\t' '{$1=$1; print}' data.csv   # CSV -> TSV
awk 'NR==5' file                        # print line 5
awk 'NR>1' data.csv                     # skip the header row

awk: Patterns & Actions

Docs: gawk(1) man page

The model is pattern { action }. The action runs only on matching lines, and a pattern alone means { print }.

awk '/ERROR/' app.log                       # grep-like
awk '$3 > 500' access.log                   # numeric comparison on a field
awk '$1 == "nginx" && $4 ~ /5[0-9][0-9]/'   # combine conditions, regex on field
awk 'NF == 0 {next} {print $1}' file        # skip blank lines
awk 'length($0) > 120' script.sh            # lines longer than 120 chars
awk '!seen[$0]++' file                      # dedupe, preserving order

awk: BEGIN / END

Docs: GNU gawk manual

awk 'BEGIN {FS=","; print "host,status"} $2=="down" {print $1","$2}' hosts.csv
awk '{total += $5} END {print "bytes:", total}' access.log
awk 'END {print NR}' file                   # line count, like wc -l
awk 'BEGIN {for (i=1; i<=5; i++) print "srv" i}'   # no input file needed

awk: Associative Arrays

Docs: GNU gawk manual

# count requests per IP, sorted by count
awk '{count[$1]++} END {for (ip in count) print count[ip], ip}' access.log | sort -rn | head

# sum bytes per status code
awk '{bytes[$9] += $10} END {for (s in bytes) print s, bytes[s]}' access.log

# join two files on field 1 (like a lookup table)
awk 'NR==FNR {owner[$1]=$2; next} {print $0, owner[$1]}' owners.txt servers.txt

The NR==FNR idiom is worth memorizing: true only while awk reads the first file, so you load it into an array, then enrich the second.

awk: printf

Docs: GNU gawk manual

awk '{printf "%-20s %8d\n", $1, $2}' file      # left-pad name, right-pad number
awk '{printf "%.2f%%\n", $1/$2*100}' file      # floats; awk does real math
awk 'BEGIN {printf "%s\t%s\n", "col1", "col2"}'

%s string, %d int, %f float, %x hex, %-10s left-justified width 10. \n is not automatic, so add it.

Common One-Liners

Docs: GNU gawk manual

TaskCommand
Sum column 3awk '{s+=$3} END {print s}' file
Average column 2awk '{s+=$2} END {print s/NR}' file
Dedupe keeping orderawk '!seen[$0]++' file
Extract between markerssed -n '/START/,/END/p' file
Pick CSV columns 1 & 4awk -F',' '{print $1","$4}' file.csv
Strip trailing whitespacesed -i 's/[ \t]*$//' file
Number all linesawk '{print NR": "$0}' file
Print file between line 100-110sed -n '100,110p' file
Comment out a config linesed -i '/^listen 80/s/^/#/' nginx.conf
Top talkers in a logawk '{print $1}' log | sort | uniq -c | sort -rn | head

More pipeline building blocks (sort, uniq, xargs, jq) live in the Bash CLI One-Liners Cheatsheet.

0

When to Use What

ToolReach for it when…
grepYou only need to find lines (fastest, simplest)
cutFixed single-char delimiter, simple column extraction
sedLine-oriented editing: substitute, delete, insert, in-place
awkFields, arithmetic, aggregation, conditions across columns
PythonNested data, JSON, anything a one-liner can’t express cleanly

Rule of thumb: grep to find, sed to change, awk to compute. If your awk program grows past a few lines, it’s a script. Commit it with a shebang and tests.

1
  • Bash Basics: quoting, conditionals, loops, and here-docs, the scripting frame these sed and awk snippets slot into
  • Bash CLI One-Liners: the rest of the pipeline toolkit (find, grep -o, sort | uniq -c, jq, and curl recipes)
  • Ubuntu Terminal: apt, systemd, journalctl, and ufw, which is where the logs and config files you’ll run these one-liners against actually live

The rest of the shell pages are in the Bash group; the full cheatsheet library has everything else.

Similar Articles

More from development

Go (Golang) Cheatsheet

Go cheatsheet covering the go toolchain, syntax essentials, goroutines and channels, table-driven …

tmux Cheatsheet

Quick-reference tmux cheatsheet: sessions, windows, panes, copy mode, synchronize-panes, .tmux.conf …

Jenkins Cheatsheet

Jenkins cheatsheet with declarative pipeline syntax, credentials, parameters, parallel stages, …

Bash Basics Cheatsheet

Quick-reference Bash basics cheatsheet: variables, parameter expansion, conditionals, loops, arrays, …