sed 102: Replace In-Place

Gabe Berke-Williams

Many people know how to use basic sed:

sed 's/hello/bonjour/' greetings.txt
echo "hi there" | sed 's/hi/hello/'

That’ll cover 80% of your sed usage. This post is about the other 20%. Think of it as a followup course after sed 101.

So you can change streams by piping output to sed. What if you want to change the file in-place?

Replacing in-place

sed ships with the -i flag. Let’s consult man sed:

-i extension
    Edit files in-place, saving backups with the specified extension.

Let’s try it:

$ ls
greetings.txt
$ cat greetings.txt
hello
hi there
$ sed -i .bak 's/hello/bonjour/' greetings.txt
$ ls
greetings.txt
greetings.txt.bak
$ cat greetings.txt
bonjour
hi there
$ cat greetings.txt.bak
hello
hi there

Note that on Linux systems, a space after -i might cause an error, so instead of -i .bak, you can try -i.bak.

So the original file contents are saved in a new file called [file_name].bak, and the new, changed version is in the original greetings.txt. Now all we have to do is:

rm greetings.txt.bak

And we’ve changed the file in-place. You are now the toast of the office, sung of by bards.

Let’s get l33t

Wait, there’s more in that man entry for sed -i:

If a zero-length extension is given, no backup will be saved.  It is not
recommended to give a zero-length extension when in-place editing files, as
you risk corruption or partial content in situations where disk space is
exhausted, etc.

Zero-length extension, eh? Let’s use our original greetings.txt file before we changed it:

$ sed -i '' 's/hello/bonjour/' greetings.txt
$ ls
greetings.txt
$ cat greetings.txt
bonjour
hi there
$ cat greetings.txt.bak
cat: greetings.txt.bak: No such file or directory

The -i '' (or, in Linux, just -i) tells sed to use a zero-length extension for the backup. A zero-length extension means that the backup has the same name as the new file, so no new file is created. It removes the need to run rm after doing an in-place replace.

I haven’t run into any disk-space problems with -i ''. If you are worried about the man page’s warning, you can use the -i .bak technique I mention in the previous section.

Find and replace in multiple files

We like sed so much that we use it in our replace script. It works like this:

replace foo bar **/*.rb

The first argument is the string we’re finding. The second is the string with which we’re replacing. The third is a pattern matching the list of files within which we want to restrict our search.

Now that you’re a sed master, you’ll love reading replace‘s source code.

What’s next

If you found this useful, you might also enjoy the Grymoire sed guide. It’s helpful when learning and as a reference.