1

how can I sort a string like, for instance

 "1.3.2 1.3.1 1.2.3 1.1.1.5"

to

"1.1.1.5 1.2.3 1.3.1 1.3.2"

So I don't know how many numbers the version consists of and I don't know how many versions there are in the string.

How to solve this?

Thanks

0

2 Answers 2

6

This is one of the few instances where NOT quoting a variable is useful.

$ string="1.3.2 1.3.1 1.2.3 1.1.1.5"
$ printf "%s\n" $string | sort -V
1.1.1.5
1.2.3
1.3.1
1.3.2

This uses GNU sort's -V aka --version-sort option to sort the numbers.

You can store that back into a variable, even the same variable ($string):

$ string=$(printf "%s\n" $string | sort -V)
$ echo $string 
1.1.1.5 1.2.3 1.3.1 1.3.2

or an array:

$ array=( $(printf "%s\n" $string | sort -V) )
$ typeset -p array
declare -a array=([0]="1.1.1.5" [1]="1.2.3" [2]="1.3.1" [3]="1.3.2")

BTW, you should almost certainly be using an array rather than a simple string with white-space separating multiple different values. The only real reason not to is if you're using a shell (like ash) that doesn't support arrays.

e.g.

$ array=( 1.3.2 1.3.1 1.2.3 1.1.1.5 )
$ typeset -p array
declare -a array=([0]="1.3.2" [1]="1.3.1" [2]="1.2.3" [3]="1.1.1.5")

$ array=( $(printf "%s\n" "${array[@]}" | sort -V) )
$ typeset -p array
declare -a array=([0]="1.1.1.5" [1]="1.2.3" [2]="1.3.1" [3]="1.3.2")
4
  • The problem is that I need to store the version numbers in an associative array. So no arrays allowed : / But thanks for the answer!
    – von spotz
    May 29, 2021 at 15:16
  • 1
    That doesn't make much sense. You can use version numbers as the keys (and/or the values) to an associative array and still keep a list of the keys in another non-associative array...which is better (as in more useful and less prone to white-space / word-splitting errors) than keeping the list of keys in a scalar variable. In fact, it's very common to do that because it's an easy way of getting the benefits of an associative array AND being able to iterate over the keys in an ordered fashion (hashes are unordered in bash)....which is, i presume, what you're wanting to do here.
    – cas
    May 29, 2021 at 15:21
  • @cas Not sure the -V option to sort is needed here.
    – ctac_
    May 29, 2021 at 17:17
  • 1
    @ctac_ -V is a natural sort, so sorts them all "correctly" (i.e. in a way that people generally expect for version numbers, e.g. 1.1.1.5 would come before 1.1.1.15 with sort -V but not with sort's default or with sort -n). BTW, GNU ls also has a -v natural sort option so you don't have to zero-pad numbers in file names, and zsh has a (n) glob modifier for natural sorting.
    – cas
    May 30, 2021 at 6:01
3

With perl:

$ s='1.3.2 1.3.1 1.2.3 1.1.1.5'
$ echo "$s" | perl -Mversion -lane 'print join " ", sort {
                   version->parse($a) cmp version->parse($b) } @F'
1.1.1.5 1.2.3 1.3.1 1.3.2

You must log in to answer this question.

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