Replace strings in files with sed, the bash command

Sed is a stream editor, meaning you can search and replace strings in files and use regex if needed. The changes can be done "in place" or save the modified content to a renamed file. This is especially good for replacing placeholder values in configuration files.

There’s a million things to sed, see the man page. This post looks into how to replace simple string in files.


Let’s imagine a file called metamorfosis.txt, with a content:

One morning, when Gregor Samsa woke from troubled 
dreams, he found himself transformed in his bed into 
a horrible vermin.

Lets replace the “vermin” with a “pony” and copy the file under different name:

$ sed 's/vermin/pony/g' metamorphosis.txt > ponymorphosis.txt

You can run that in the prompt, or put it into a file and run the file.

Replace in place

-i for “in place”, it means that no copy of the file will be created.

$ sed -i 's/vermin/pony/g' metamorphosis.txt

Using variables as replace and search values

Variables can be used just as well, only they need to be interpolated and the first sed argument needs to be double quoted, instead of singular. Here’s it wrapped into a function:

ponyfyer() {
    local search=$1
    local replace=$2
    # Note the double quotes
    sed -i "s/${search}/${replace}/g" metamorphosis.txt

This is the time to note that there are two flavours of sed, the Linux sed, and the FreeBSD sed. As OS X branched from Next, and Next came from BSD, uses OS X the FreeBSD flavoured sed. Which is a bit different, see the FreeBSD man page for details.

The BSD sed needs a backup file when replacing in place, we don’t really want to use a backup file, so we have define an empty backup file. Note the empty pair of quotes after the -i:

ponyfyer() {
    local search=$1
    local replace=$2
    sed -i "" "s/${search}/${replace}/g" metamorphosis.txt

Otherwise it’ll throw an error:

sed: 1: "/Users/user/path/ponyf ...": extra characters at the end of h command

Now on we’re gonna use the OS X sed.

Replace an array of values

Let’s pick less silly example, a config file where we replace %%placeholder%% values. Below is the contents of the config file:

# config.php
define( 'DB_NAME', '%%DB_NAME%%' );
define( 'DB_USER', '%%DB_USER%%' );
define( 'DB_PASSWORD', '%%DB_PASSWORD%%' );
define( 'DB_HOST', '%%DB_HOST%%' );

And this is the contents of the script file:

# Associative array where key represents a search string,
# and the value itself represents the replace string.
declare -A confs

configurer() {
    # Loop the config array
    for i in "${!confs[@]}"
        # Note the "" after -i, needed in OS X
        sed -i "" "s/${search}/${replace}/g" config.php

We end up with readily configured file:

# config.php
define( 'DB_NAME', 'bobs_db' );
define( 'DB_USER', 'bob' );
define( 'DB_PASSWORD', 'hammertime' );
define( 'DB_HOST', 'localhost' );

Note: when using a loop, we have to use the in place option.

Replacing values with forward slashes in them

If a value is, say, a URL and it has / in it, then sed returns an error similar to this:

sed: 1: "s/%%PRODUCTION_DEPLOY_T ...": bad flag in substitute command: 'v'

Or the almost identical:

sed: 1: "s/%%APP_REPO%%/git@gith ...": bad flag in substitute command: 'e'

There’s two ways to deal with this:

  1. Escape the values, more here
  2. Don’t use forward slash as a separator in sed

Let’s concentrate on the latter. The separator doesn’t have to be /, it can be anything, like a pipe |, for instance:

sed -i "" "s|${search}|${replace}|g" config.php

The character can be anything, as long as all the separators are the same:

sed -i "" "s♥${search}♥${replace}♥g" config.php


sed is pretty powerful, like cooking with gas.


Club-Mate, the beverage →