Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

awk sed perl to merge rows based on keyword match

Tags:

bash

sed

awk

perl

I've been banging my head head against the wall on this issue due to my limited awk/sed wizardry. I'm happy to use awk,sed,bash,perl, or whatever to accomplish this text manipulation.

I have the following output and would like to merge lines based on a sort of key match:

 Node: server1
 Active Server: SECONDARY
 Standby Server: PRIMARY
 Primary 192.168.1.1
 Secondary 192.168.1.2

 Node: server2
 Active Server: PRIMARY
 Standby Server: SECONDARY
 Primary 10.1.1.1
 Secondary 10.1.1.2

Desired output:

 Node: server1
 Active Server: Secondary 192.168.1.2
 Standby Server: Primary 192.168.1.1

 Node: server2
 Active Server: Primary 10.1.1.1
 Standby Server: Secondary 10.1.1.2

So I need the lines to merge based on the words "primary" and "secondary". My first thought was to change "Primary" to "PRIMARY" so it would be easier to match.

My eventual goal is to have this:

 server1,Active,192.168.1.2,Standby,192.168.1.1
 server2,Active,10.1.1.1,Standy,10.1.1.2

(but I can figure this part out after help merging the rows)

Thanks for the help!

like image 359
jaredwins Avatar asked Dec 12 '25 17:12

jaredwins


2 Answers

This Perl solution seems to do what you ask. It simply pulls the values into a hash line by line, and dumps the hash contents when all the required values are present.

Update I've used any from List::Util in place of grep to make the code more legible.

use strict;
use warnings;
use autodie;

use List::Util 'any';

my @names = qw/ node active standby primary secondary /;

open my $fh, '<', 'myfile.txt';

my %server;

while (my $line = <$fh>) {
  next unless my ($key, $val) = lc($line) =~ /(\w+).*\s+(\S+)/;

  %server = () if $key eq 'server';
  $server{$key} = $val;

  unless ( any { not exists $server{$_} } @names ) {
    printf "%s,Active,%s,Standby,%s\n", @server{'node', $server{active}, $server{standby}};
    %server = ();
  }
}

output

server1,Active,192.168.1.2,Standby,192.168.1.1
server2,Active,10.1.1.1,Standby,10.1.1.2
like image 183
Borodin Avatar answered Dec 15 '25 20:12

Borodin


It is dense and very ugly multi-liner,

perl -00 -nE'
  s/ ^(\w+)\s+([\d.]+)\s* / $s{$1}=$2; ""/xmge;
  ($l=$_) =~ s! \s*\w+:\s*|\n !,!xg;
  $l =~ s|\U$_|$s{$_}| for keys %s;
  ($_=$l) =~ s/^,|,$//g;
  say
' file

output

server1,Active,192.168.1.2,Standby,192.168.1.1
server2,Active,10.1.1.1,Standby,10.1.1.2

Explanation

# -00 => instead of single line read lines into $_ until \n\n+
perl -00 -nE'
  # read and remove 'Primary|Secondary IP' into $s{Primary} = IP
  s/ ^(\w+)\s+([\d.]+)\s* / $s{$1}=$2; ""/xmge;

  # replace 'something:' or new line by ','
  ($l=$_) =~ s! \s*\w+:\s*|\n !,!xg;

  # replace SECONDARY|PRIMARY with actual IP address
  $l =~ s|\U$_|$s{$_}| for keys %s;

  # remove ',' at beginning and end of the string
  ($_=$l) =~ s/^,|,$//g;

  # print result
  say
' file
like image 20
mpapec Avatar answered Dec 15 '25 19:12

mpapec



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!