sed: editing a config in place
Replace a value in a config with sed, without opening an editor.
In a deploy script, or during an incident, you often need to change one
value in a config: a port, a database address, a debug flag. Opening an
editor on the server takes too long, and inside a script it's not even
possible. That's what sed is for: it reads the file line by line, applies
a command to each line, and prints the result. With the -i flag, it
writes the result back to the file.
Where to practice
The examples below work in an ubuntu:24.04 container (GNU sed). You can
bring up the same one yourself:
docker run --rm -it ubuntu:24.04 bash
On Linux and in WSL2, the commands work in your own terminal too. On
macOS, sed is different (the BSD one), and the -i flag is written
differently there. More on that in "Common mistakes".
Create a config to try this on:
printf 'host=localhost\nport=8080\nworkers=4\nmax_workers=16\n' > /tmp/app.conf
The s command: find and replace
The main sed command is s/old/new/:
sed 's/8080/9090/' /tmp/app.conf
host=localhost
port=9090
workers=4
max_workers=16
Without -i, the file doesn't change: the result only goes to the screen.
Check it: cat /tmp/app.conf will show the old port=8080. That's how you
should start any edit: look at the output first, then write.
The quotes are single, so the shell doesn't touch the characters inside the expression.
First match or all: the g flag
Without a flag, s changes only the first match in each line. The g
flag at the end changes all of them:
printf 'a a a\n' | sed 's/a/b/'
b a a
printf 'a a a\n' | sed 's/a/b/g'
b b b
sed goes through all the lines either way. g only affects repeats
within a single line.
The pattern is matched as a substring
Whatever is on the left in s/.../.../ is searched for anywhere in the
line. That's the main trap: the replacement touches similar lines.
sed 's/workers=4/workers=8/' /tmp/app.conf
host=localhost
port=8080
workers=8
max_workers=16
Here you got lucky. But like this, max_workers changes too, because it
contains workers=1:
sed 's/workers=1/workers=2/' /tmp/app.conf
host=localhost
port=8080
workers=4
max_workers=26
To make the pattern match only the whole line, there are anchors: ^
means the start of the line, $ the end. s/^workers=4$/workers=8/ will
touch only the line that equals workers=4 exactly.
The value isn't always known ahead of time. That's where .* comes in:
the dot means any character, the asterisk repeats it any number of times.
s/^port=.*/port=9090/ will replace the port= line regardless of its
value.
Preview what will change: -n and p
On a large config, reading the whole output is inconvenient. The -n
flag turns off printing of all lines, and p after s prints only the
lines where the replacement happened:
sed -n 's/^port=.*/port=9090/p' /tmp/app.conf
port=9090
If nothing got printed, the pattern didn't match any line. If more lines got printed than you expected, the pattern is too broad.
Editing in place: -i
-i (in-place) writes the result to the same file and prints nothing:
sed -i 's/^port=8080$/port=9090/' /tmp/app.conf
grep port /tmp/app.conf
port=9090
-i.bak saves a copy with the .bak suffix before editing:
sed -i.bak 's/^port=9090$/port=7070/' /tmp/app.conf
After that, /tmp/app.conf will have port=7070, and
/tmp/app.conf.bak will have the previous port=9090. You can roll back
with a plain mv.
Several replacements in one pass are given with -e:
sed -i -e 's/^a=1$/a=5/' -e 's/^b=2$/b=6/' file.
Special characters
Regular expressions work in the pattern on the left, so a few characters don't mean themselves:
.is any character.s/1.2/1.3/will replace both1.2and1x2. To search for a literal dot, escape it:s/1\.2/1.3/.^,$,*,[,]are also special. Escape them with\.
On the right, there's one special character, &: it substitutes the
matched text. sed 's/web/R&D/' will turn web into RwebD. If you need
the literal character, write \&.
Delimiter and variables
The / delimiter isn't mandatory. You can put any character after s,
and it becomes the delimiter: s|old|new| or s#old#new#. You need this
when the value contains /, for example a path or a URL. With / as the
delimiter, sed will take a slash inside the value as the end of the
expression.
In scripts, the value is often stored in a variable. The shell substitutes variables only inside double quotes:
PORT=9090
sed "s/^port=.*/port=$PORT/" /tmp/app.conf
In single quotes, $PORT would end up in the file literally, as the text
$PORT.
Common mistakes
- A replacement without anchors touches neighboring lines:
s/port=80/port=81/will change bothport=8080andadmin_port=80. Before-i, run it without it, or with-n ... p, and see which lines would change. sed 's/a/b/' file > fileleaves an empty file: the shell truncatesfilefor writing beforesedeven starts reading it. For in-place edits, there's-i.- The pattern didn't match, and
sedstays silent: exit code 0, the file unchanged. For example,s/debug=TRUE/.../against a linedebug=true: case matters. After-i, check the result withgreporcat. unknown option tos'means there's an extra delimiter in the expression. Most often it's a/` from a substituted URL or path. Pick a different delimiter.- macOS: BSD
sed's-irequires an argument.sed -i 's/a/b/' filefails there with an error likesed: 1: "file": ..., because the expression ends up as the backup suffix. On macOS, writesed -i '' 's/a/b/' file, but GNUseddoesn't understand that form.sed -i.bak '...' fileworks on both: you delete the backup afterward.
What you'll need for the tasks
- Replace a value with
s/old/new/and write it to the file with-i. - Narrow the pattern with
^and$anchors, so you don't touch similar lines. - Check what will change with
sedwithout-i, or withsed -n '...p'. - Change the delimiter when the value contains
/. - Substitute a variable's value inside double quotes.
Practice in your browser
Linux runs right here. Solve the task and we'll save your progress automatically.
Turn off debug
/etc/app.conf has a line debug=true. Change it to debug=false. Don't use vi/nano, do it with sed -i directly on the file.
0%
Go through it with an AI agent
The agent explains anything unclear in plain words, gives you 2 labs for this lesson and drills you on interview questions. $49 one-time, lifetime access.
Tell the agent: use MCP izi, give me lesson terminal-text-02-sed-replace
Progress saved in this browser
Clear your history or open this on your phone, and the marks will be gone. Leave your email and they'll move to your account. No password needed.
Done. moved to your account. You can see your progress on any device. My progress