Some versions of sort can easily sort IPv4 addresses into natural order
Every so often I need to deal with a bunch of IPv4 addresses, and
it's most convenient (and best) to have them sorted into what I'll
call their natural ascending order. Unfortunately for sysadmins,
the natural order of IPv4 addresses is not their lexical order (ie
sort will give you), unless you zero-pad all of their octets.
In theory you can zero pad IPv4 addresses if you want, turning
18.104.22.168 into 058.172.099.001, but this form has two flaws; it
looks ugly and it doesn't work with a lot of tools.
(Some tools will remove the zero padding, some will interpret
zero-padded octets as being in octal instead of decimal, and some
will leave the leading zeros on and not work at all;
dig -x is
one interesting example of the latter. In practice, there are
much better ways to deal with this problem and people who zero-pad
IPv4 addresses need to be politely corrected.)
Fortunately it turns out that you can get many modern versions of
sort to sort plain IPv4 addresses in the right order. The trick is
to use its
-V argument, which is also known as
in at least GNU coreutils. Interpreting IPv4 addresses as version
numbers is basically exactly what we want, because an all-numeric
MAJOR.MINOR.PATCH.SUBPATCH version number sorts in exactly the same
way that we want an IPv4 A.B.C.D address to sort.
Unfortunately as far as I know there is no way to sort IPv6 addresses into a natural order using common shell tools. The format of IPv6 addresses is so odd and unusual that I expect we're always going to need a custom program for it, although perhaps someday GNU Sort will grow the necessary superintelligence.
This is a specific example of the kind of general thinking that you need in order to best apply Unix shell tools to your problems. It's quite helpful to always be on the lookout for ways that existing features can be reinterpreted (or creatively perverted) in order to work on your problems. Here we've realized that sort's idea of 'version numbers' includes IPv4 addresses, because from the right angle both they and (some) version numbers are just dot-separated sequences of numbers.
PS: with brute force, you can use any version of
sort that supports
-k to sort IPv4 addresses; you just need the right magic
arguments. I'll leaving working them out (or doing an Internet
search for them) as an exercise for the reader.
PPS: for the gory details of how GNU sort treats version sorting,
see the Gnu sort manual's
section on details about version sort.
Okay, technically it's
ls's section on version sorting. Did you know
that GNU coreutils ls can sort filenames partially based on version numbers?
I didn't until now.
(This is a more verbose version of this tweet of mine, because why should I leave useful stuff just on Twitter.)
Sidebar: Which versions of
sort support this
When I started writing this entry, I assumed that
sort -V was a
GNU coreutils extension and would only be supported by the GNU
coreutils version. Unixes with other versions (or with versions
that are too old) would be out of luck. This doesn't actually appear
to be the case, to my surprise.
Based on the GNU Coreutils NEWS file, it appears that '
appeared in GNU coreutils 7.0 or 7.1 (in late 2008 to early 2009).
The GNU coreutils sort is used by most Linux distributions, including
all of the main ones, and almost anything that's modern enough to be
getting security updates should have a version of GNU sort that is
recent enough to include this.
Older versions of FreeBSD appear to use an old version of GNU
coreutils sort; I have access to a FreeBSD 9.3 machine that reports
/usr/bin/sort is GNU coreutils sort 5.3.0 (from 2004,
apparently). Current versions of FreeBSD and OpenBSD have switched
to their own version of
sort, known as version '2.3-FreeBSD', but
this version of
sort also supports
-V (I think the switch
happened in FreeBSD 10, because a FreeBSD 10.3 machine I have access
to reports this version). Exactly how
-V orders things is probably
somewhat different between GNU coreutils sort and FreeBSD/OpenBSD
sort, but it doesn't matter for IPv4 addresses.
/usr/bin/sort is very old, but I know that OmniOS
/usr/gnu/bin/sort as standard and really you want
early in your
$PATH anyways. Life is too short to deal with ancient
Solaris tool versions with ancient limitations.