In Place File Editing With P̸e̸r̸l̸ Ruby
Ever had to change the URL in 50 files? What do you do?
vi *.html
(You should know by now I’d use Emacs.)
Or whip up a Bash script with sed
?
Since dinosaurs roamed the Earth, I’ve been using Perl’s In Place
Editing feature -i
.
perl -p -i.orig -e 's/bar/baz/' file
Let’s break it down, shall we? -e
is the code to
execute, you can do something as simple as:
perl -e 'print "Hello\n"'
-p
changes the meaning of -e
. Instead of executing the code once,
it loops over the input files and applies the code to each
line. In Ruby it would look like:
while gets
# -e code runs here
end
In Perl you could implement the classic Cloud to Butt with:
perl -p -e 's/cloud/butt/ig' file
This will output the contents of the file with all occurrences of cloud replaced with butt.
That brings us to -i
. -i
says edit the file in place. Instead of
printing the modified contents of the file, it replaces the file with
the new version. (Note to the Pedantic, -i
isn’t actually original
to Perl, it’s one of the ideas Perl took from sed
. It just happens
to be where I learned it.) This can be a little scary, the sed
docs
say:
If [no argument] 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.
So, -i
takes an optional argument which is used to name a backup
copy the original file. Thus…
perl -p -i.orig -e 's/bar/baz/g' file
Copies file into file.orig and saves a new version with bar replaced by baz. If you give it multiple files, each one is backed-up and then processed.
perl -p -i.orig -e 's/bar/baz/g' file0 file1 ... fileN
Oh, and multiple -e
arguments are fine if you terminate each one
with a “;”.
perl -p -i.orig -e 's/bar/baz/g;' -e s/foo/teh fooz/g' file0 file1 ... fileN
which is the same as:
perl -p -i.orig -e 's/bar/baz/g; s/foo/teh fooz/g' file0 file1 ... fileN
Why on Earth am I telling you this on a primary Ruby blog? Because everything I just told you works in Ruby as well. The only difference is the code:
ruby -p -i.orig -e 'gsub(/bar/,"baz")' file0 file1 ... fileN
And the fact that Ruby doesn’t need semicolons if you use multiple
-e
arguments. (It does, of course, if you combine them in one -e
argument.)
ruby -p -i.orig -e 'gsub(/bar/,"baz")' -e 'gsub(/foo/,"teh foo")' file0 file1 ... fileN
What’s it good for? The above URL change, of course (.ly is sooo last year).
ruby -p -i.orig -e 'gsub('http://example.ly','http://example.io)' *.html
The links will be changed and the original files backed up as .html.orig
And don’t forget that you can use pattern matching with
#gsub
. Consider the directive to add decimal places to all prices in
a file:
ruby -p -i.orig -e 'gsub(/\$(\d+)/, "\\0.00")' prices.txt
So next time you find yourself opening a bunch of files to do a search and replace, instead throw Ruby at it and get it done in no time.
Comments