AWK swapping fields on different lines

Hi All,

Sorry if this question has been posted elsewhere, but I'm hoping someone can help me! Bit of an AWK newbie here, but I'm learning (slowly!)

I'm trying to cobble a script together that will save me time (is there any other kind?), to swap two fields (one containing whitespace), with each field on different lines

As an arbitrary example (I'll explain as best as I can!):

ENTRANT LIST
 
Name         Entry Type    Fastest Time
--------------------------------------------
Andrew         Cyclist          10:59        #(newline here)
Cyclist Mr. Smith has a great track record....

******************************
Chris             Runner          45:12
Runner Mr. Jones has been an avid runner for....
******************************

Now my problem is this: I want to Switch $1 of the first line ("Andrew") with $2 of the second line ("Mr. Smith" [note whitespace]) to give me:

ENTRANT LIST
 
Name         Entry Type    Fastest Time
--------------------------------------------
Mr. Smith         Cyclist          10:59        #(newline here)
Cyclist Andrew has a great track record....

******************************

Im assuming I'll need to use the *s as record separator and operate from there, but I'm coming up short on:

A) How to read two lines at once - presumably I will need a third area in memory to store one of the fields while the other is moved- should I create a temp file for this?

B) Avoiding having 'Mr. Smith' separated into two fields.

I'm trying to avoid creating two arrays if possible, but I can see this being the only way - does anybody have any suggestions about how I could approach this another way?

Sorry for all the questions - hopefully someone can help me out!

 
$ nawk '{a=$1;b=$0;getline;c=$2" "$3;sub(c,a);sub(a,c,b);printf("%s\n%s",b,$0)}' test.txt
Mr. Smith Cyclist 10:59 #(newline here)
Cyclist Andrew has a great track record....
 
$ cat test.txt 
Andrew Cyclist 10:59 #(newline here)
Cyclist Mr. Smith has a great track record....

1 Like

And there it is, in black and white.

Thanks for such a quick and elegant solution - my thought process was way off!

Thanks itkamaraj!

And for something a little cryptic.. :wink:

sed '/^[-*]/{N;N;s/\(\n\)\([^ \t]*\)\(.*\n[^ \t]*[ \t]*\)\([^ \t]*[ \t]*[^ \t]*\)/\1\4\3\2/;}' infile
sed '/^[-*]/{N;N;s/\(\n\)\([^ ]*\)\(.*\n[^ ]* *\)\([^ ]* *[^ ]*\)/\1\4\3\2/;}' infile
sed -E '/^[-*]/{N;N;s/(\n)([^ ]*)(.*\n[^ ]* *)([^ ]* *[^ ]*)/\1\4\3\2/;}' infile
1 Like
sed '/^[-*]/{N;N;s/\(\n\)\([^ \t]*\)\(.*\n[^ \t]*[ \t]*\)\([^ \t]*[ \t]*[^ \t]*\)/\1\4\3\2/;}' infile

Catchy, and easy to remember :slight_smile:

Thanks for that, Scrutinizer (and for sorting out the tags in my original post).

Working my way through the O'reilly Sed and Awk book at the moment - Aside from applying the knowledge gained to anything and everything I can, does anyone have any recommendations for resources following on from this?

Sorry for straying off-topic a little!

If you want to try perl:

perl -lane 'if ( /^\s*(\w+)\s+\w+\s+(\d\d:\d\d).*/) {$L1=$_;$name=$1;next}
            if ($L1 && $name ne "" ){
                  s/^\s*(\w+\s)(.*)(\s+has.*)/$1$name$3/;$surn=$2;
                  $L1 =~ s/^(\s*)(\w+)(\s+.*)/$1$surn$3/;
                  print $L1."\n".  $_;undef $L1;undef $name;
             }else {print $_}' infile
ENTRANT LIST
 
Name         Entry Type    Fastest Time
--------------------------------------------
Mr. Smith         Cyclist          10:59        #(newline here)
Cyclist Andrew has a great track record....

******************************
Mr. Jones             Runner          45:12
Runner Chris has been an avid runner for....
******************************