A friend of mine recently showed me his version of extracting ip address(es) from ifconfig. The ifconfig tool on Linux is used to list IP addresses and configure network interfaces. It is sometimes necessary to capture your IP in a variable, like when writing some firewall rules.

I decided to show off and golf the extraction of IP address with four commonly used tools -- Awk, sed, a version of Perl everyone has, and the latest version of Perl 5.10.

His original version was pretty ugly:

$ ifconfig | perl -ple 'print $_ if /inet addr/ and $_ =~ s/.*inet addr:((?:\d+\.){3}\d+).*/$1/g ;$_=""' | grep -v ^\s*$

My own version on my firewall was:

$ ifconfig | grep inet | awk -F: '{ print $2 }' | awk '{ print $1 }'

This looks nicer but I was uselessly using grep, and calling awk twice.

Golfing in Perl

My first attempt was to do it with grep and Perl.

$ ifconfig | grep inet | perl -ple '($_) = /addr:([^ ]+)/' 192.168.1.1 127.0.0.1

In a split second I realized that Perl does grep itself:

$ ifconfig | perl -nle '/addr:([^ ]+)/ and print $1' 192.168.1.1 127.0.0.1

Then I noticed that 'dr:' matches the same lines as 'addr:'; also 'and' can be replaced with '&&':

$ ifconfig | perl -nle '/dr:([^ ]+)/ && print $1' 192.168.1.1 127.0.0.1

The regular expression '([^ ]+)' can be replaced with '(\S+)', which matches non-whitespace characters:

$ ifconfig | perl -nle '/dr:(\S+)/ && print $1' 192.168.1.1 127.0.0.1

Cutting the whitespace, the final version for Perl is 37 characters long:

$ ifconfig|perl -nle'/dr:(\S+)/&&print$1' 192.168.1.1 127.0.0.1

Golfing in Perl 5.10

It can be made shorter with Perl 5.10, which introduces the new say function:

$ ifconfig|perl -nE'/dr:(\S+)/&&say$1' 192.168.1.1 127.0.0.1

The result for Perl 5.10 is 34 characters.

Golfing in sed

Then I also tried doing the same with sed:

$ ifconfig | sed -n '/dr:/{;s/.*dr://;s/ .*//;p;}' 192.168.1.1 127.0.0.1

I modified it to strip off everything that was not numbers and dots:

$ ifconfig | sed -n '/dr:/{;s/.*dr:\([0-9.]\+\) .*/\1/;p;}' 192.168.1.1 127.0.0.1

This turned out to be much longer, so I tried getting rid of backslashes, by enabling extended regexes in sed with -r argument:

$ ifconfig | sed -rn '/dr:/{;s/.*dr:([0-9.]+) .*/\1/;p;}' 192.168.1.1 127.0.0.1

I forgot that I had used the ([^ ]+) regex before. Another my friend reminded me this, shortening the sed script to:

$ ifconfig | sed -rn 's/.*r:([^ ]+) .*/\1/p' 192.168.1.1 127.0.0.1

Dropping the whitespace, sed version turned out to be 40 characters long.

Golfing in Awk

My final attempt was to optimize my original Awk version:

$ ifconfig | awk '/dr:/{gsub(/.*:/,"",$2);print$2}' 192.168.1.1 127.0.0.1

Cutting the whitespace, the Awk version is 43 characters.

The Winner

The winner in this golf tournament is Perl 5.10 with 34 chars!

Can You Do Better?

Can you golf this even shorter?

PS. my awk and sed cheat sheets might come handy!