Tuesday, May 18, 2010

Perl find and replace

SkyHi @ Tuesday, May 18, 2010

1. The good - The simple case

Sometimes you want to change the same pattern in a lot of files. How can you do that?

Now, vi and emacs can both open a lot of files, eg: vi *.html. And you can then do a search and replace on the same pattern. But here's a neat perl trick that sometimes comes in useful:

Suppose you have a bunch of files (file1, file2, file3 etc) which have the same chunk of text in them. Eg, the text:

Newspapers are about news.

In a fit of disgust at the tripe that is printed in the Sunday Spurt, you decide to change the statement to

Newspapers are about selling advertising space.

Then this perl in-place edit one-liner comes in handy here:

$ perl -pi -e 's/about news\.$/about selling advertising space\./' file*

Tada! You're done.

The flags (perldoc perlrun) work like this:

-p              loop and swallow the files, and print default.

-i edit the files in-place

-e do the command



How to do a search and replace over multiple files

You could also use find and sed, but I find that this little line of perl works nicely.

perl -pi -w -e 's/search/replace/g;' *.php
-e means execute the following line of code.
-i means edit in-place
-w write warnings
-p loop

Example I had the following style sheet in a section:

<link rel="stylesheet" type="text/css" href="../includes/style.css">

and I wanted the following instead:

<link rel="stylesheet" type="text/css" href="admin.css">

As each expression is a regular expression you've got to escape the special characters such as forward slash and .


So the final line of code ends up as

perl -pi -w -e 's/\.\.\/includes\/style\.css/admin\.css/g;' *.php



Perl Oneliner: Recursive Search and Replace

If you’ve used Perl at all you are probably familiar with the simple oneliner to do a search and replace on a given string:

perl -p -i -e 's/oldstring/newstring/g' *

This will replace all occurrences of oldstring with newstring in all of the files in your current directory. Being able to do this quickly and easily is absolutely awesome, but what if you want to do this recursively across the current directory and all directories below that? I’m sure that there are plenty of ways to do this, the one below is the method that seems the easiest:

perl -p -i -e 's/oldstring/newstring/g' `find ./ -name *.html`

If you wanted to be more precise you could replace find with grep and only perform the search and replace on files that you know already contain oldstring, like this:

perl -p -i -e 's/oldstring/newstring/g' `grep -ril oldstring *`

This is one of those things that I don’t have to do very often, but when I do, this Perl oneliner is a real life saver.


$ perl -pi.bak -e 's/host\-ip 5\\\.3\\\.220\\\.101/host\-ip 5\.3\.220\.102;' c:\ips-test\*.txt