Last updated on Feb 27th, 2015 but started on Aug 18th, 2014 and marked as cli perl regex server

Replace strings in a text file using Perl

If you need to replace certain text in a file, you can use any editor you like. But if you need to change multiple occurences of the same text in multiple files it is quite a tedious job of opening them one at a time and do a manual find-and-replace routine for every one of them. In that case it is far easier and much faster to use Perl’s inline find-and-replace command:

perl -p -i -w -e "s/{PATTERN}/{REPLACEMENT}/;" /path/to/file

So what does this mean?

Flag Description
-p Prints the contents of $_ each time around the loop.
-i Edit <> files in place (and makes a backup if an extension is supplied).
-w Displays useful warnings.
-e Define Perl code to be executed by the compiler. For example: perl -e 'print "Hello World\n"'

(If you want to make a backup, replace -i with -i.bak and a backup file with this extension will be created.)

The part following -e is the command that is going to be executed and it consists of a regular expression with some useful modifiers.

The main part of the command is the so-called substitution operator: s///. This is an extension to the match operator that allows us to replace the text matched with some new text. The basic form of the operator is:

s/PATTERN/REPLACEMENT/;

PATTERN is the regular expression for the text that we are looking for. REPLACEMENT is a specification for the text or regular expression that we want to use to replace the found text with.

The regular expression can be customized using these substitution operator modifiers:

Modifier Description
i Makes the match case insensitive.
m Specifies that if the string has newline or carriage return characters, the ^ and $ operators will now match against a newline boundary, instead of a string boundary.
o Evaluates the expression only once.
s Allows use of . to match a newline character.
x Allows you to use white space in the expression for clarity.
g Replaces all occurrences of the found expression with the replacement text.
e Evaluates the replacement as if it were a Perl statement, and uses its return value as the replacement text.

The modifiers are placed after the last / of the operator. For example, s/dog/cat/ig; will replace all occurences of the text dog with cat, regardless if any of the characters of dog is in uppercase.

At the end we find the file that we’re going to update. This can be a single file, but it is also possible to use wildcards to change multiple files at the same time.

Recursive find and replace

Years have gone by where I happily used the above method to replace text in a bunch of files. Never had I the need to replace files in the directory and underlying subdirectories. Which is such an obvious case!

So, here are a couple of ways to recursively find and replace text in files. The first one seems the easiest, but will cause problems if there are for instance spaces in the filenames:

perl -p -i -w -e "s/{PATTERN}/{REPLACEMENT}/g" `find . -type f -name *.html`

Another simple solution is to use grep to find the files with the {PATTERN} before sending it to perl:

perl -p -i -w -e "s/{PATTERN}/{REPLACEMENT}/g" `grep -ril {PATTERN} *`

It regex’es files twice (first for the grep and then for perl again), so it will be quite slow when dealing with large and/or many files.

Probably the most foolproof method is this one:

find . -type f -name "*.html" -print0 | xargs -0 perl -p -i -w -e "s/{PATTERN}/{REPLACEMENT}/g"

This will pipe the results of the find command to xargs which passes it on to the perl find-and-replace we use all the time.