Sign in
← Terminal: text and search
3 min · easy · Lesson 2 of 5

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:

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

What you'll need for the tasks

Practice in your browser

Linux runs right here. Solve the task and we'll save your progress automatically.

01

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.

{ i }

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.

Get access for $49

Tell the agent: use MCP izi, give me lesson terminal-text-02-sed-replace