27

This is the data what I want to sort. But sort treats the numeric to string, the data it no sorted as I expected.

/home/files/profile1
/home/files/profile10
/home/files/profile11
/home/files/profile12
/home/files/profile14
/home/files/profile15
/home/files/profile16
/home/files/profile2
/home/files/profile3
/home/files/profile4
/home/files/profile5
/home/files/profile6
/home/files/profile7
/home/files/profile8
/home/files/profile9

I want to sort this to,

/home/files/profile1
/home/files/profile2
/home/files/profile3
/home/files/profile4
/home/files/profile5
/home/files/profile6
/home/files/profile7
/home/files/profile8
/home/files/profile9
/home/files/profile10
/home/files/profile11
/home/files/profile12
/home/files/profile14
/home/files/profile15
/home/files/profile16

Is there a good way by bash script? I can't use ruby or python script in here.

5

3 Answers 3

46

This is very similar to this question. The trouble is that you have an alphanumeric field that you are sorting on, and -n doesn't treat that sensibly, however version sort (-V) does. Thus use:

sort -V

Note that this feature is currently supported by the GNU, FreeBSD and OpenBSD sort implementations.

5
  • Do you know how portable is this? This option doesn't seem to be part of the POSIX spec.
    – Ernest A
    Commented Mar 22, 2015 at 12:12
  • @ErnestA: You are right, this is GNU sort specific solution. Added a note.
    – Thor
    Commented Mar 23, 2015 at 5:18
  • @ErnestA: I looks like FreeBSD and OpenBSD have added this feature.
    – Thor
    Commented Oct 3, 2016 at 14:21
  • And it doesn't work if the numbers have different prefixes.
    – Dante
    Commented Mar 18, 2017 at 21:23
  • 1
    To any readers: Note that this is a CAPITAL V! Use sort -V not sort -v. It's hard to tell at first glance. Commented Nov 11, 2019 at 7:33
22

You can use a temporary sentinel character to delimit the number:

$ sed 's/\([0-9]\)/;\1/' log | sort -n -t\; -k2,2 | tr -d ';'

Here, the sentinel character is ';' - it must not be part of any filename you want to sort - but you can exchange the ';' with any character you like. You have to change the sed, sort and tr part then accordingly.

The pipe works as follows: The sed command inserts the sentinel before any number, the sort command interprets the sentinel as field delimiter, sorts with the second field as numeric sort key and the tr command removes the sentinel again.

And log denotes the input file - you can also pipe your input into sed.

1
  • I like the way you resolved the problem :)
    – SHW
    Commented Jun 26, 2012 at 11:29
7

If all your file names have the same prefix before the final numeric part, ignore it when sorting:

sort -k 1.20n

(20 is the position of the first digit. It's one plus the length of /home/files/profile.)

If you have several different non-numeric parts, insert a sentinel.

You must log in to answer this question.

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