Perl Conditional Replace Depending On Match

So, as I write patches for various awful build systems, one of the things I try to do is slim down the patch file and make it easier to read. Changing ‘foobar-1.orig’ to just a and ‘foobar-1’ to just b makes a difference. Rather than manually edit the patch file, I turn to my dear friend, the regex search-and-replace. But, it gets to be a bit tiring editing essentially the same regex twice to get nearly identical results.

Take for example this little snippet of a real patch:

diff -Naurw pgpool-II-3.2.0.orig/pgpool.conf.sample pgpool-II-3.2.0/pgpool.conf.sample
--- pgpool-II-3.2.0.orig/pgpool.conf.sample    2012-07-19 03:06:21.000000000 -0400
+++ pgpool-II-3.2.0/pgpool.conf.sample    2012-08-14 07:33:39.200695855 -0400
@@ -31,10 +31,8 @@
 port = 9999
                                    # Port number
                                    # (change requires restart)
-socket_dir = '/tmp'
+socket_dir = '@PGSQL_SOCKETDIR@'
                                    # Unix domain socket path
                                    # (change requires restart)

Now, I’d like to have a line that doesn’t wrap, and I’d like to save a few bytes of precious disk space, by changing the ‘pgpool-II-3.2.0.orig’ and ‘pgpool-II-3.2.0’ bits into a shorter ‘a’ and ‘b’, respectively.

Previously, I’ve used sed, but I would run it twice. That’s a pain. I have to make sure I run the sed commands in the right order so I don’t shoot myself in the foot and have to go back to running diff again to produce the patch.

There must be a better way.

There is.

Perl’s  “easy things easy and hard things possible” attitude allowed me to arrive at a short one-liner that allows me accomplish the task:

perl -pi -e 's/pgpool-II-3\.2\.0(\.orig)?/$1?a:b/eg' run_paths.patch

The secret is in the /e modifier. /e evaluates the replacement portion of the search-and-replace expression. So, the match/search portion looks for ‘pgpool-II-3.2.0’ and if it has ‘.orig’ it captures that and stores it into $1. The replacement portion evaluates $1. If it is a true value — not undef, an empty string, or 0 — the replacement string is a, otherwise it is b.

This one-liner handily transforms the above patch into a logically identical, more aesthetically pleasing, lighter-weight version.

diff -Naurw a/pgpool.conf.sample b/pgpool.conf.sample
--- a/pgpool.conf.sample    2012-07-19 03:06:21.000000000 -0400
+++ b/pgpool.conf.sample    2012-08-14 07:33:39.200695855 -0400
@@ -31,10 +31,8 @@
 port = 9999
                                    # Port number
                                    # (change requires restart)
-socket_dir = '/tmp'
+socket_dir = '@PGSQL_SOCKETDIR@'
                                    # Unix domain socket path
                                    # (change requires restart)

Leave a Reply