3

Given input with mixed text and numbers (w/o leading zeros), how can I get it sorted in the "natural" order? For example, given the following input (hostnames):

whatever-1.example.org
whatever-10.example.org
whatever-11.example.org
whatever-12.example.org
whatever-13.example.org
whatever-2.example.org
whatever-3.example.org
whatever-4.example.org
whatever-5.example.org
whatever-6.example.org
whatever-7.example.org
whatever-8.example.org
whatever-9.example.org

I would like this output:

whatever-1.example.org
whatever-2.example.org
whatever-3.example.org
whatever-4.example.org
whatever-5.example.org
whatever-6.example.org
whatever-7.example.org
whatever-8.example.org
whatever-9.example.org
whatever-10.example.org
whatever-11.example.org
whatever-12.example.org
whatever-13.example.org

EDIT

I should have mentioned that in addition to the "whatever"s there would also be

thingaroo-#.example.org
      .
      :

blargh-#.example.org
      .
      :

...etc...

Thanks!

5 Answers 5

8

If you have GNU coreutils ≥ 7.0, then you can use version sort. This is lexicographic order except that sequences of digits are ordered according to their value as an integer in decimal notation.

sort -V
1
  • This appears to be the simplest answer. Commented Mar 12, 2016 at 17:02
2

That particular style of input could be successfully be sorted with

sort -t - -nk2,2

but it doesn't really generalize to all sorts filenames, if that's what you are looking for.

2
  • Upvoted for being the only one to mention this is not a general solution.
    – Wildcard
    Commented Mar 11, 2016 at 7:51
  • This answer was very helpful in coming up with what I really wanted (see my question edit and answer). Thanks! Commented Mar 11, 2016 at 13:34
2

Sorry, I didn't give all the info needed in my original question. All the answers were useful to me in coming up with what I really wanted. What I ended up using was:

sort -t- -k1,1 -k2,2

where:

-t-       divide the hostnames into fields using dash (-) rather than spaces
-k1,1     the first sort key is the first field (from 1 to 1), a normal sort
-k2,2     the second key is the second field using a numeric (n) sort
          (the field includes the ".example.org" but the numeric sort
          seems to cope find with the trailing non-number chars)

this gives the result:

blargh-1.example.org
    :
blargh-13.example.org
thingaroo-1.example.org
    :
thingaroo-17.example.org
whatever-1.example.org
    :
whatever-13.example.org
1
  • Ah - good point :-o Commented Mar 11, 2016 at 16:22
1

Assuming whatever in your text can vary, you need to use sort with the following options:

-t, --field-separator=SEP use SEP instead of non-blank to blank transition

k, --key=POS1[,POS2] start a key at POS1 (origin 1), end it at POS2 (default end of line)

-V, --version-sort natural sort of (version) numbers within text

sort -t "-" -k 2 -V < [filename]
1
  • This worked to sort them all by the numbers. All the "1"s, then all the "2"s etc. This was not what I wanted here, but still good to know. Commented Mar 11, 2016 at 13:18
0
sort -t- -k2n file

whatever-1.example.org
whatever-2.example.org
whatever-3.example.org
whatever-4.example.org
whatever-5.example.org
whatever-6.example.org
whatever-7.example.org
whatever-8.example.org
whatever-9.example.org
whatever-10.example.org
whatever-11.example.org
whatever-12.example.org
whatever-13.example.org

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .