Perl版本号排序代码精简及管道化运行方法问询
Great question! Let's break this down into two parts: cleaning up your existing sort logic, and plugging it into a pipeline to process input like a list of versions from stdin or a file.
First: Simplify the Sort Code
Your current custom sort works, but we can make it way cleaner (and more robust) by using Perl's core version module—it's been part of Perl since 5.10, so no extra installs are needed. This module handles all the tricky edge cases of version comparison automatically: different segment counts, leading zeros, even alpha/beta tags if you ever need them.
Here's the simplified sort block that replaces your original code:
sort { version->parse($a) <=> version->parse($b) } @versions
If for some reason you can't use the version module (though I'd strongly recommend it), we can refactor your original logic to be more concise without losing functionality:
sort { my @left = split /\./, $a; my @right = split /\./, $b; # Compare each segment until we find a difference for my $i (0 .. $#left) { return $left[$i] <=> $right[$i] if $left[$i] <=> $right[$i]; } # If all matching segments are equal, shorter version comes first return @left <=> @right; } @versions
This loops through each version segment until it finds a mismatch, then falls back to comparing the length of the version strings (so 1.2 comes before 1.2.3, which is correct).
Second: Integrate into a Pipeline
To use this in a pipeline (like processing output from another command or a file with one version per line), we can turn it into a Perl one-liner that reads from stdin, sorts, and prints the result.
Recommended: Using the version Module
Let's say you have a file versions.txt with versions listed line-by-line, or you're piping output from a command like cat versions.txt. Run this:
cat versions.txt | perl -Mversion -ne 'push @versions, $_; END { print sort { version->parse($a) <=> version->parse($b) } @versions }'
Or a slightly shorter version that slurps all input at once:
perl -Mversion -0777 -ne 'print sort { version->parse($a) <=> version->parse($b) } split /\n/, $_' versions.txt
Pure Regex Pipeline (No Modules)
If you absolutely can't use the version module, here's the refactored custom sort as a one-liner:
cat versions.txt | perl -ne 'push @v, $_; END { print sort { my @l=split/\./,$a; my @r=split/\./,$b; for my $i(0..$#l){return $l[$i]<=>$r[$i] if $l[$i]<=>$r[$i]} return @l<=>@r } @v }'
Example Output
Suppose your input file has these versions:
1.10 1.2 1.9.3 2.0 1.2.1
Running the pipeline command will output them sorted correctly:
1.2 1.2.1 1.9.3 1.10 2.0
Why the version Module is Worth Using
- Handles edge cases: It correctly compares versions with leading zeros (like
1.02vs1.1—1.02is older, which your original code does right, but the module formalizes this). - Supports pre-release versions: If you ever need to sort alpha/beta tags like
1.2.3_01or2.0-beta1, it works out of the box. - Readability: It's much easier to understand at a glance than custom comparison logic.
内容的提问来源于stack exchange,提问作者Jim

