You pose an interesting challenge. Try this Perl script:
#!/usr/bin/perl
use warnings;
use strict;
use integer;
# This script sorts filenames while respecting their ordinal component,
# outputting 'dir/stem9.ext' before 'dir/stem10.ext'. As input, it
# expects one filename per line on stdin.
our $n_digits = 6;
sub compare_filenames_ordinally ($$) {
my ($a, $b) = @_;
my $pattern = qr|^(.*?)(\d*)((?:\.[^/\d]*)?)$|;
my ($stem_a, $ordinal_a, $extension_a) = $a =~ /$pattern/;
my ($stem_b, $ordinal_b, $extension_b) = $b =~ /$pattern/;
length($ordinal_a) <= $n_digits && length($ordinal_b) <= $n_digits
or die "$0: the ordinal part of the filename "
. "is longer than $n_digits digits\n";
my $ordinal_a1 = length($ordinal_a)
? sprintf "%0${n_digits}d", $ordinal_a : '';
my $ordinal_b1 = length($ordinal_b)
? sprintf "%0${n_digits}d", $ordinal_b : '';
my $a1 = "${stem_a}${ordinal_a1}${extension_a}";
my $b1 = "${stem_b}${ordinal_b1}${extension_b}";
return $a1 cmp $b1;
}
my @file = <>;
chomp for @file;
@file = sort { compare_filenames_ordinally $a, $b } @file;
print "$_\n" for @file;
The script undoubtedly could be improved, not least because it repeats some lines of code with respect to $a
and $b
, but its idea is that it extends the likes of dir/stem10.txt to dir/stem000010.txt before comparing it against other filenames.