How can I numerically sort a single line of delimited items?

With gawk (GNU awk) for the asort() function:

gawk -v SEP='*' '{ i=0; split($0, arr, SEP); len=asort(arr);
    while ( ++i<=len ){ printf("%s%s", i>1?SEP:"", arr[i]) }; 
        print "" 
}' infile

replace * as the field separator in SEP='*' with your delimiter.



You can also do with the following command in case of a single line (because it's better leave it alone of using shell-loops for text-processing purposes)

tr '.' '\n' <<<"$aline" | sort -n | paste -sd'.' -

replace dots . with your delimiter.
add -u to the sort command above to remove the duplicates.

Notes:
You may need to use -g, --general-numeric-sort option of sort instead of -n, --numeric-sort to handle any class of numbers (integer, float, scientific, Hexadecimal, etc).

$ aline='2e-18,6.01e-17,1.4,-4,0xB000,0xB001,23,-3.e+11'
$ tr ',' '\n' <<<"$aline" |sort -g | paste -sd',' -
-3.e+11,-4,2e-18,6.01e-17,1.4,23,0xB000,0xB001

In awk no need change, it still will handling those.


Using perl there's an obvious version; split the data, sort it, join it back up again.

The delimiter needs to be listed twice (once in the split and once in the join)

eg for a ,

perl -lpi -e '$_=join(",",sort {$a <=> $b} split(/,/))'

So

echo 1,100,330,42 | perl -lpi -e '$_=join(",",sort {$a <=> $b} split(/,/))'
1,42,100,330

Since the split is a regex, the character may need quoting:

echo 10.1.200.42 | perl -lpi -e '$_=join(".",sort {$a <=> $b} split(/\./))'
1.10.42.200

By using the -a and -F options, it's possible to remove the split. With the -p loop, as before and set the results to $_, which will automatically print:

perl -F'/\./' -aple '$_=join(".", sort {$a <=> $b} @F)'

Using Python and a similar idea as in Stephen Harris' answer:

python3 -c 'import sys; c = sys.argv[1]; sys.stdout.writelines(map(lambda x: c.join(sorted(x.strip().split(c), key=int)) + "\n", sys.stdin))' <delmiter>

So something like:

$ cat foo
10.129.3.4
1.1.1.1
4.3.2.1
$ python3 -c 'import sys; c = sys.argv[1]; sys.stdout.writelines(map(lambda x: c.join(sorted(x.strip().split(c), key=int)) + "\n", sys.stdin))' . < foo
3.4.10.129
1.1.1.1
1.2.3.4

Sadly having to do the I/O manually makes this far less elegant than the Perl version.