2

I have some data sets (foo) with bar and baz as output in sections'. Sections with baz should be sorted to be at the top of the output.

Example input;

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

In above example, I would like section = foo3 = and = foo5 = to be moved to the top of the output, and have the list sub-sorted by section "name", ie.

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

but with the contents of the section intact.

2 Answers 2

2

Lottastuff solution, 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'

The initial transformation is darn too picky. There should be some tool capable of pasting lines until delimiter (:

Sign up to request clarification or add additional context in comments.

1 Comment

I had considered a similar approach, but it just seemed too damned messy in the end. Thank you for taking the time to suggest it, though :)
1

Perl solution. It uses a hash of sections, the key is the name of a section, the value contains the position in the file where the section starts and the information whether baz was present. Once the file is read into the hash, the keys are sorted and the contents is printed, moving around the file as remembered.

#!/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;
    }
}

3 Comments

Works completely as advertised, was a quick and easily legible answer. Would and will read again A++.
As an aside, I also have "dead"/empty sections - can I discard those with another elsif?
@Jan: Well, empty sections would go through the first if branch. You can set a section to nonempty once it contains anything, i.e. even before checking /baz/. You can skip seeking the empty sections when outputting.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.