Follow me on Twitter for my latest adventures!

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?


Facebook
Plurk
more
GitHub
LinkedIn
FriendFeed
Google Plus
Amazon wish list
Comments
Even shows ipv6 addresses, if you have them.
ip addr sh | awk '/inet/{print$2}'Oh dear it's so hard to put code and text on
the same page! (It's never done in books,
of course). I know! Let's put all the code
into little tiny scrolling text boxes! That'll
show em!!!!
My first thought was the same as Uriah, though it ended up being a bit shorter anyway:
ip a | awk '/inet/{print $2}'
'ip a' is one of my most-oft-typed 4-character strings; I currently get 61 from `history | grep ip a | wc -l`.
Uriah && Vineet Kumar, good one!
Eddie Pasternak, weeeeeee! Thanks for your feedback, that will be redesigned in the new version of catonmat!
Umm, hello? netstat -in
y, umm...
& will do just as well as && in the perl version, I suspect.
Staying with ifconfig, Ruby's puts is one character longer than Perl 5.10's say, but uses the very same technique, showing the similarities between both languages:
ifconfig|grep Bcast|awk ' { print $2 }'|awk -F":" ' { print $2 }'
Thank yew ! Owesome ;)
Here's a bash/grep version:
/sbin/ifconfig | grep "inet addr" | grep -v "ddr: " | while read a b c ; do echo $b ; done | ( IFS=':' ; while read a b ; do echo $b ; done )
This is my version...
ifconfig|egrep -o 'dr:[^ ]+'|sed 's/dr://g'
Here is the same in Scheme:
(let ([o (open-output-string)]) (parameterize ([current-output-port o]) (system "ifconfig")) (regexp-match* #rx"(?<= inet addr:)[0-9.]*" (get-output-string o)))
Here's a Python version. We're going for the longest one-liner, right?:
ryant@spitfire:~$ ifconfig | python -c "import sys; import re; print re.match(re.compile('.*addr:([0-9\.]*)\s.*'), [ln for ln in sys.stdin.readlines() if ln.find('inet')>=0][0]).group(1)" 192.168.10.10440 characters
Oh yeah, Nemelc! Nice one! :)
gethostip -d `hostname`
ifconfig | awk '/inet addr/{print substr($2,6)}'
I don't understand the counting, so just compare the length:
That looks like 28 characters for the simple version vs 36 (not 34) for the "winner".
simpleton, just count the characters in the string.
ifconfig|perl -nE'/dr:(\S+)/&&say$1' is 34 characters not 36 as you suggest. Just 'echo -n ... | wc -c' it!
Your solution does not quite work. It does not list 127.0.0.1. Also, and IP can take 15 chars max (xxx.xxx.xxx.xxx), and you cut just 10...
Yep, you are right, mine won't work because of IP address length problems.
A corrected version using grep and cut is ~45 characters.
ifconfig|grep t\ a|cut -d" " -f12|cut -d: -f2
I still think you aren't counting right though. Please count the characters in:
ifconfig|perl -nE'/dr:(\S+)/&&say$1'
by hand, and you will get 36.
See:
Compare:
"$1" is getting expanded to nothing, and you lose those characters in the count.
What if your system has no free entries in its process table and you are *desperately* in need of your IPv4? This can happen… in some planets.
Here's a version for Linux without any fork()s, in the major shells that support string slicing/substrings. In some proud ~220 characters.
bash/ksh:
iface=eth0; while read Iface x x x x x x x x x x x x x SpecDst x; do [ "$Iface" = $iface ] && for i in 6 4 2 0; do echo -n $((0x${SpecDst:i:2})); ((i==0)) || echo -n .; done && echo && break; done < /proc/net/rt_cachezsh:
iface=eth0; while read Iface x x x x x x x x x x x x x SpecDst x; do [ "$Iface" = $iface ] && for i in 7 5 3 1; do echo -n $((0x${SpecDst[i,i+1]})); ((i==1)) || echo -n .; done && echo && break; done < /proc/net/rt_cacheI wonder if this is easier to read from any other place than the routing cache.
Cheers.
Try this
ifconfig -a|grep inet|cut -d" " -f2
One more character less than above
ifconfig -a|grep ine|cut -d" " -f2
suresh, it does not work:
Even if you meant ':', it does not work:
Sorry I forget to put Double quotas
please correct it as follow
ifconfig -a|grep ine|cut -d" " -f2
you can also use single quota instead of double quota as quoted by Mr.Peteris
Looks like that's due to the differences in the output formats on different machines.
On Solaris, the following works - 33 chars:
ifconfig -a|awk '/inet/{print$2}'
or even the following - 32 chars:
ifconfig -a|awk '/ine/{print$2}'
If you don't mind a little extra whitespace, here's a shorter one (I won't even use 5.10 :)
It's a little tougher to get a WAN address from a router. Here's the best I could do:
Note the fake ip address "1.2" as argument to traceroute.
On another distro, one could leave out the -N 1 option to traceroute, but it's broken in Ubuntu Intrepid and won't do fewer than 6 hops without -N 1.
remember GNU awk fields can be set using regex.
ifconfig | awk -F':| *' '/inet /{print $4}'
bash on Ubuntu 8.04:
ip a|awk '/g/{print$2}'23 characters
The 'g' matches in the word 'global', the scope value of the address, which is not on the line with the loopback address. As a bonus with this style, you also get the CIDR mask of the net.
Even better:
ipa(){ ip a|awk '/g/{print$2}';}Then you can type 'ipa' anytime you want. Put it in .bashrc for persistence. Name it 'i' instead and you have a one character command to get your IP address.
schemer, haha about 'i' :)
The shortest solution using ip and awk:
Even shorter:
These all fail miserably if you have "ne", "net" or "inet" in an interface's name, which is perfectly possible.
But back to ifconfig,
So how about getting the IPv6 address without the mask?
1. Can you write a short shell to find any IPV4 IP addresses in any files under /var/lib/*. Perform a dns reverse. Lookup for each IP found, and format the output neatly, like “IP=192.168.0.1, hostname=jo.blogg.com. http://jo.blog.com“?
hostname -i
11 characters, but only returns the IP address associated with the hostname.
ifconfig|awk '-F[ :]+' '/inet addr:/{print $4}'
if you want iface->IP:
ifconfig|awk '-F[ :]+' '/^[a-z]/{i=$1}/inet addr:/{print i,$4}'
ifconfig|awk '-F[ :]+' '/inet addr:/{print $4}'
if you want iface->IP:
ifconfig|awk '-F[ :]+' '/^[a-z]/{i=$1}/inet addr:/{print i,$4}'
other form with grep and regex:
ip addr sh wlan0 | grep -E -o "([0-9]+.){3}[0-9]+" | head -1ifconfig | grep -E -o "([0-9]*\.){3}[0-9]"
ifconfig | grep -E -o "[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*"
| grep -E -o "([0-9]{1,3}\.){3}[0-9]{1,3}" | sort -t. -k1,1n -k2,2n -k3,3n -k4,4n | uniq
:D
time ifconfig eth0 | awk '/inet adr:/ { print substr($2,5,length($2)) }' #real 0m0.009s #user 0m0.001s #sys 0m0.010stime ifconfig eth0 | grep 'inet adr:' | cut -d: -f2 | awk '{ print $1}' #real 0m0.014s #user 0m0.003s #sys 0m0.017stime TOTO=$(ifconfig eth0); TOTO=${TOTO##*adr\:}; TOTO=${TOTO%% *} #real 0m0.007s #user 0m0.002s #sys 0m0.004stime ip addr show eth0 | awk '/inet/ { print substr($2,0,length($2)-3) }' #real 0m0.007s #user 0m0.001s #sys 0m0.009stime TOTO=$(ip addr show eth0); TOTO=${TOTO##*inet}; TOTO=${TOTO%%/*}; echo $TOTO #real 0m0.005s #user 0m0.002s #sys 0m0.004s#ifconfig eth0 | sed -n 2p | cut -d ":" -f2
172.168.1.100 Bcast
And to exclude the 'Bacast' word you add a second cut
#ifconfig eth0 | sed -n 2p | cut -d ":" -f2 | cut -d " " -f1
172.168.1.100
ifconfig -a | awk '/inet\ / { print $2 }'
Leave a new comment