Thursday, August 9, 2007

As easy as -p -i -e

Before the advent of the World Wide Web and the decoding of the human genome, PERL had already ensconced itself in the IT world amongst *NIX system administrators almost ten years prior. For good reason. PERL provides a more complete feature set than the Bourne Shell and/or sed/awk. Then and now, all of these tools are commonly used by system administrators to automate repetitive tasks.

One of my favorite invocations of PERL is with the command line options -p -i -e. This particular combination allows for the in place editing of files, namely searching for one string and replacing it with another. Like so:

perl -p -i -e 's/original_text/replacement_text/' configuration_file

You can even qualify the -i parameter to back up the file being modified:

perl -p -i.bak -e 's/original_text/replacement_text/' configuration_file

The original file will continue to live on as configuration_file.bak.

Recently, a coworker was faced with changing a configuration file to point from one database to another on six production instances of Oracle's Application Server. Each instance in turn housed ten applications. This meant he would need to go edit sixty configuration files or use Oracle's web based administration tool and drill into it sixty times. Irrespective of which of these methods you employ, the process is tedious and error prone.

Armed with such knowledge, cobbling a solution for my coworker's plight did not take long. Logging into any number of machines via a script is one reason the Secure Shell(ssh) exists. Since I administer the boxes the changes needed to be done on, I had the requisite private cryptographic key to log into all of them without being prompted for a password.

This problem beckoned for automation since I could readily traverse all of the machines from a central point and invoke commands. In summary, I wanted to log into each machine, find the configuration files of interest, do an in place substitution to point to a different database.

Here is the solution for saving my coworker from firing up vi sixty times across six machines:

for i in `echo "mach1 mach2 mach3 mach4 mach5 mach6"`; do
ssh $i 'cd /oracle/10gR3; find . -name "data-sources.xml" | xargs perl -p -i.bak -e "s/oracle/microsoft/" ';
done


The for loop is a shell construct executed on the system that serves as my jumping point to reach each system where I employed ssh-agent to avoid password prompting. Ultimately the heart of what I am doing on each machine is this:

cd /oracle/10gR3
find . -name "data-sources.xml" | xargs perl -p -i.bak -e "s/oracle/microsoft/"

I situate myself in the base directory of the Oracle application server, find all the copies of the configuration file in question, data-sources.xml, then use xargs to invoke PERL to do in place substitution against each and every instance of said configuration file. Using find with the -exec option and removing the intermediate xargs invocation works equally well.

So now, instead of wasting an hour (or more) editing sixty files, we both can hit the golf course an hour early.

This experience underscores the potency of using several seemingly disparate tools to solve a problem - very much the *NIX way of doing things. Now if only I could do these kinds of things "out of the box" under Windows...

1 comment:

Gas Creature said...

It's odd that you would write `echo "mach1 ... mach6"` because you could have just listed them: mach1 ... mach6. Don't know if the machine names are simplified for the purpose of the blog, but at any rate, you can also provide a sequence spec like mach[1-6] or mach? to catch all the single-digit machines. The perl pie trick is good though.