排序文本部分(unix / shell)

时间:2013-07-29 12:00:48

标签: bash unix sorting

我有一些数据集(foo),其中barbaz作为部分输出。带baz的部分应排序到输出的顶部。

示例输入;

= foo4 =
bar
(..)
barN
= foo1 =
bar
(..)
barN
= foo5 =
bar
(..)
barN
baz
= foo2 =
bar
(..)
barN
= foo3 =
bar
(..)
barN
baz

在上面的示例中,我希望将= foo3 == foo5 =部分移动到输出的顶部,并将列表按“name”部分进行子排序,即。

= foo3 =
= foo5 =
= foo1 =
= foo2 =
= foo4 =

但该部分的内容完好无损。

2 个答案:

答案 0 :(得分:2)

Lottastuff解决方案,a.k.a。, fat-oneliner

awk '/^=/{print ""} {printf "%s\t", $0}' input.txt | \
    awk '{print ($NF != "baz")"\t"$0}' | sort -n | cut -f 2- | \
    tr '\t' '\n' | sed -e '/^$/d'

最初的转变过于挑剔。应该有一些工具能够粘贴行直到分隔符(:

答案 1 :(得分:1)

Perl解决方案。它使用部分的散列,键是部分的名称,该值包含部分开始的文件中的位置以及是否存在baz的信息。将文件读入哈希后,将对键进行排序并打印内容,并在记住的文件中移动。

#!/usr/bin/perl
use warnings;
use strict;

my $file = shift;

my $start = qr/^= (.*) =$/;

open my $FH, '<', $file or die $!;

my %sections;
my $current_section;
while (<$FH>) {
    if (/$start/) {
        $current_section = $1;
        $sections{$current_section}{begin} = tell $FH;
    } elsif (/baz/) {
        $sections{$current_section}{baz} = 1;
    }
}

for my $section (map substr( $_, 1),
                 sort map { ($sections{$_}{baz} ? '0' : '1') . $_ }
                 keys %sections) {
    seek $FH, $sections{$section}{begin}, 0;
    print "= $section =\n";
    while (<$FH>) {
        last if /$start/;
        print;
    }
}