Search-and-replace across a stream or file is the single most common text edit in scripts and one-liners.
sed (stream editor) reads input line by line into its pattern space, applies your commands, prints the result and moves on. The command you'll use 90% of the time is substitution:
sed 's/old/new/' file- Without flags only the first match on each line is replaced. Add
gfor all matches, or a number (2) for the second only. I(GNU) makes the match case-insensitive.- In the replacement,
&stands for the whole matched text:s/[0-9]*/<&>/wraps the number. - The delimiter can be any character.
s|/usr/local|/opt|avoids escaping every slash in paths. - Pass several commands with
-eor separate them with;.
The pattern is a BRE by default, just like grep. Use sed -E for ERE so +, ?, | and parentheses work without backslashes.
sed writes to standard output and leaves the input file untouched; redirect to a new file or use -i (next lessons) when you are sure. To insert a literal & or the delimiter in the replacement, escape it: \&, \/.
Remember that . in the pattern matches any character: s/1.0/2.0/ also changes 100. Escape it (1\.0) when you mean a dot.
Example
echo 'one cat, two cats, red cat' | sed 's/cat/dog/'
# one dog, two cats, red cat
echo 'one cat, two cats, red cat' | sed 's/cat/dog/g'
# one dog, two dogs, red dog
echo 'one cat, two cats, red cat' | sed 's/cat/dog/2'
# one cat, two dogs, red cat
echo 'price 42' | sed 's/[0-9][0-9]*/[&]/' # price [42]
echo 'path=/usr/local/bin' | sed 's|/usr/local|/opt|' # path=/opt/bin
echo 'v1.0 and 100' | sed 's/1\.0/2.0/g' # v2.0 and 100
echo 'Hello World' | sed -e 's/Hello/Bye/' -e 's/World/all/' # Bye allRemember
- s/pattern/replacement/ changes the first match; add g for all
- & in the replacement is the whole match
- Pick another delimiter (s|a|b|) when the text contains slashes
Watch out for
- Expecting s/x/y/ to replace every occurrence on a line; without g only the first changes.