Я думаю, будет справедливо сказать, что sed
не является правильным инструментом для этой задачи. С достаточными усилиями, вероятно, можно было бы сделать это, но это действительно несправедливо.
Perl (или Python) - разумная альтернатива. Я лучше владею Perl, чем Python, поэтому я бы использовал это.
Кроме того, с Perl вам, вероятно, даже не нужно отправлять вывод в несколько файлов, если размер документа не превышает сотни мегабайт.
Я читаю между строк немного, но я думаю, что ваш формат ввода документа примерно такой:
2.1.9
...multiple lines of material for section 2.1.9...
1.3.6
...multiple lines of material for section 1.3.6...
9.1.3
...multiple lines of material for section 9.1.3...
Где разделы представлены не по порядку. Это не имеет решающего значения для моего предположения, что тег раздела находится на отдельной строке; он незначительно меняет вещи, если в одной строке есть текст.
В общих чертах код должен выглядеть следующим образом:
my $current_section = "0.0.0";
my %section_list = ();
my $section_material = "";
while (<>)
{
if (m/^(\d+\.\d+\.\d+)/)
{
# Found a new section...stash the old one...
if ($section_material ne "")
{
# If the same section number appears twice, simply concatenate
# the new material over the old. Or you can get more complex,
# using an array of refs to section material...
$section_list{$current_section} = ""
if !defined $section_list{$current_section};
$section_list{$current_section} .= $section_material;
$current_section = $1;
$section_material = "";
}
}
$section_material .= $_;
}
if ($section_material ne "")
{
$section_list{$current_section} = ""
if !defined $section_list{$current_section};
$section_list{$current_section} .= $section_material;
}
# Now the hash %section_list contains all the material.
# You need a section number comparison function that can be used with sort
sub section_cmp
{
...if $a comes before $b...return -1
...if $b comes before $a...return +1
...otherwise...............return 0
}
foreach my $section (sort section_cmp keys %section_list)
{
print "[$section]\n";
print "$section_list{$section}\n";
}
И теперь у вас есть вывод с разделами в отсортированном порядке, без каких-либо промежуточных файлов.
Код является контурным. Я не полностью его изучил; это, вероятно, не минимально. В частности, фьюзинг с гарантией $section_list{$current_section}
является пустым, если его не использовать раньше, что может легко привести к параноидальному излишеству. Другие детали, которые я должен тщательно проверить, это вызов функции сравнения в sort
и механика функции сравнения.
Код сравнения ниже работает так, как я ожидаю. Я не уверен, что нет более умного способа сделать сравнение более лаконичным, но работать лучше, чем работать. Это небольшая независимая программа с тестовым набором:
#!/usr/bin/env perl
use strict;
use warnings;
my @array = ( "3.1.6", "1.2.9", "7.4.5", "2.1.3", "10.1.2", "1.1.1",
"1.1.3", "1.4.9", "1.4", "1.4.9.1", "1.10.13", "1.1.13" );
# For use from sort - data 'passed' as $a and $b
sub paranum_cmp
{
my(@v1) = split /\./, $a;
my(@v2) = split /\./, $b;
my($l1) = scalar @v1;
my($l2) = scalar @v2;
my($len) = ($l1 < $l2) ? $l1 : $l2;
for (my $i = 0; $i < $len; $i++)
{
return -1 if ($v1[$i] < $v2[$i]);
return +1 if ($v1[$i] > $v2[$i]);
}
return -1 if ($l1 < $l2);
return +1 if ($l1 > $l2);
return 0;
}
print "Before:\n";
foreach my $v (@array) { print "$v\n"; }
@array = sort paranum_cmp @array;
print "After:\n";
foreach my $v (@array) { print "$v\n"; }
Вы можете найти v-числа или найти модуль «сравнения версий», который бы выполнял работу быстрее.