{{{ #!/usr/bin/perl -w use strict; # Read all lines from STDIN or file my @lines = <>; # Remove terminating newline from each line foreach (@lines) { chomp } # Function to compare version numbers like "7.1.2" sub compare_version_numbers { my ($l,$r) = @_; my @lx = split("\\.",$l); my @rx = split("\\.",$r); my $minlen = (@lx < @rx) ? @lx : @rx; for (my $i=0; $i < $minlen; $i++) { # make numeric by multiplying with 1 my $l_number = ($lx[$i] * 1); my $r_number = ($rx[$i] * 1); # compare with spaceship operator my $l_vs_r = ($l_number <=> $r_number); # return if decision is clear! if ($l_vs_r != 0) { return $l_vs_r } # otherwise, next part in array of version numbers } # if we are here, we could not decide - shortest entry wins! return @lx <=> @rx } # Function to compare whole paths like "client_release/7.2/7.2.25" # As it is called from "sort", the values are passed in via "$a" and "$b" sub compare_paths { my @ax = split("/",$a); my @bx = split("/",$b); my $minlen = (@ax < @bx) ? @ax : @bx; for (my $i=0; $i < $minlen; $i++) { # Check whether we have version numbers at position $i my $a_is_vnum = ($ax[$i] =~ /^[\d\.]+$/); my $b_is_vnum = ($bx[$i] =~ /^[\d\.]+$/); if ($a_is_vnum && !$b_is_vnum) { # "a" version number before "b": b wins return 1 } if (!$a_is_vnum && $b_is_vnum) { # "b" is version number before "a": a wins return -1 } if (!$a_is_vnum && !$b_is_vnum && $ax[$i] ne $bx[$i]) { # both are not version numbers and both are unequal: compare the strings return $ax[$i] cmp $bx[$i] } if ($a_is_vnum && $b_is_vnum && $ax[$i] ne $bx[$i]) { # both are unequal version numbers: compare the version number # print STDERR $ax[$i] . " vs " . $bx[$i]; my $sn = compare_version_numbers($ax[$i],$bx[$i]); # print STDERR " = " . $sn . "\n"; if ($sn != 0) { return $sn } } # otherwise, next part in array of path elements } # if we are here, we could not decide - shortest entry wins! return @ax <=> @bx } # Sort and print my @sorted = sort compare_paths @lines; foreach (@sorted) { print "$_\n" } }}}