sed 102: Replace In-Place

sed 102: Replace In-Place

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

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 '' 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:

  • sed by example taught me sed. It’s a great resource in an easy-to-follow format.
  • The Grymoire sed guide is also an easy-to-follow guide that starts off easy and dives deep. It’s helpful when learning and as a reference.

Hound reviews Ruby and CoffeeScript code for style violations and comments on your GitHub pull requests. Free for open source repos.