Preview a replacement, then edit
diff shows every changed line before and after:
sed edits and deletes lines by pattern, awk splits lines into fields and computes over them, line by line.
sed -n 's/old/new/p' app.ini
preview the changed lines
sed -i.bak 's/old/new/g' app.ini
edit, keep app.ini.bak
sed -n '5,10p' file
lines 5 to 10
sed '/^ *#/d; /^$/d' file
drop comments and empty lines
sed '/^ *#/! s/old/new/' file
replace outside comments
awk '{print $1}' access.log
the first field of every line
awk -F: '$3 >= 1000 {print $1}' /etc/passwd
filter by a field
awk '{s += $4} END {print s}' log.txt
sum of the fourth field
sed and awk read text line by line — from a file or a
pipeline — and print the result. The file stays as it was
until sed gets the -i option.
s/pattern/replacement/ changes text, d
deletes a line, p prints it.$1, $2… and runs an action for the
lines that match a condition.On the lab machines sed is GNU sed 4.9 and awk is GNU awk 5.2.
s/pattern/replacement/flags. The pattern is a
regular expression; the flags are g — every match in the line
(otherwise only the first), p — print the changed line, I — ignore case.
Any character after s works as the delimiter: s#/old/path#/new/path# is
handier when the pattern contains /.
A dot in a pattern means any character, so an unescaped address matches too much:
10.20.0.150 matched as well. The pattern 10\.20\.0\.15: with escaped dots
and a trailing colon matches only the address you mean.
A command can be limited to certain lines:
| Address | Lines |
|---|---|
5 |
the fifth |
5,10 |
the fifth to the tenth |
$ |
the last |
/^db_host/ |
those matching the pattern |
/^ *#/! |
all except those matching |
A ! after an address inverts it. This is how a replacement skips commented
lines:
With -E (extended expressions), parentheses ( ) capture part of the match,
and \1, \2 insert it into the replacement:
Both spellings of the key, with and without spaces, now look the same, and the
comment is untouched because the pattern starts with ^. Without -E,
parentheses are plain characters and \1 has nothing to refer to (see the
invalid reference problem below).
An awk program is a set of condition {action} pairs. $0 is the whole line,
$1… are fields, NF is the number of fields, NR is the line number. A
condition compares a field ($4 == "refund"), checks the line number
(NR > 1 skips a header) or matches a pattern (/error/). Without a condition
the action runs for every line; without an action a matching line is printed
whole.
An END {…} block runs after the last line, and an array s[key] collects
values by key:
The order of for (k in s) is undefined, hence the sort. Fields are split on
spaces and tabs; -F sets another separator: awk -F: … for /etc/passwd,
awk -F, … for CSV without quotes.
The main options of both programs are in the table below. The full lists are in
man sed and man gawk.
| Option | What it does | Example |
|---|---|---|
-i SUFFIX |
sed — edit the file in place; with no argument, keeps no backup. dangerous | sed -i.bak 's/old/new/g' file |
-n |
sed — suppress automatic printing; paired with the p command. | sed -n '5,10p' file |
-F SEP |
awk — set the field separator instead of the default whitespace. | awk -F: '{print $1}' /etc/passwd |
-E |
sed — extended regular expressions (no need to escape groups). | sed -E 's/(a|b)+/X/g' file |
-v var=val |
awk — pass a variable value into the program. | awk -v n=5 '{print $n}' file |
Nothing found. Try a shorter query.
diff shows every changed line before and after:
The list of files first, the edit second: that way you see what will change.
The pattern matched no line. Run the same replacement with -n … p: empty
output means the pattern is the problem — case, spaces around =, a dot or
* without \.
The pattern is wider than needed: an unescaped dot matched any character,
there is no ^ at the start, no address excludes comments. Check the
sed -n … p output before editing.
sed 's/a/b' is missing the last delimiter. The full command is
s/pattern/replacement/.
The pattern or the replacement contains /, and sed took the rest for flags.
Change the delimiter: s#/old/path#/new/path#.
The replacement has \1, but the pattern has no group: without -E,
parentheses are plain characters. Add -E or write the group as \(…\).
A brace or a quote in the program is not closed:
Put the awk program in single quotes, so the shell does not expand $1.
The line is split with the wrong separator: /etc/passwd uses :, CSV uses a
comma. Set -F.
sed -i rewrites the file without asking. A wrong pattern applied to many
files at once (*.conf) can only be undone from backups: use -i.bak and
check the replacement with -n … p before editing.
sed -i writes the result to a temporary file and moves it over the old one.
A symbolic link turns into a regular file, and a hard link stops pointing at
the edited content. For links, use --follow-symlinks or edit the target.
s and addresses.sed -i.Found an inaccuracy? Report an error in the article