gablin
gablin

Reputation: 4808

How to process two result files using awk?

I have two files which both follow the same pattern:

TEST CASE 1:  0.004 seconds
TEST CASE 2:  0.043 seconds
TEST CASE 3:  0.234 seconds
TEST CASE 4:  0.564 seconds
....

What I'm trying to do is calculate the speedup for each test case, which is done by taking the value from one file and dividing it with the corresponding value in the other file.

Is there a simple way of doing that using awk?

Upvotes: 3

Views: 871

Answers (3)

gablin
gablin

Reputation: 4808

I managed to come up with my own solution by using paste to merge the two result files. Then the awk script became really simple, and the test cases are sorted correctly.

paste <(grep "^TEST CASE" file1) <(grep "^TEST CASE" file2) |
awk '{print "TEST CASE " $3 "  " $4 / $9}'

The grep is there to get the expected input to paste as the lines are taken from a file which contains a lot of other information that I don't want. If the expected output is already available in a separate file (as I stated in the question), then the command becomes

paste file1 file2 | awk '{print "TEST CASE " $3 "  " $4 / $9}'

This gives as output:

TEST CASE 1:  1.0423
TEST CASE 2:  2.34023
TEST CASE 3:  3.2423
TEST CASE 4:  4.3425
....

Upvotes: 1

paxdiablo
paxdiablo

Reputation: 882786

If they have the same test cases, you can simply combine the two files in a sorted manner then use awk to process the resultant stream, storing the first time for each pair and then calculating on the second time.

Something like in the following transcript:

pax:~$ cat file1
TEST CASE 1:  0.004 seconds
TEST CASE 2:  0.043 seconds
TEST CASE 3:  0.234 seconds
TEST CASE 4:  0.564 seconds

pax:~$ cat file2
TEST CASE 1:  0.003 seconds
TEST CASE 2:  0.040 seconds
TEST CASE 3:  0.134 seconds
TEST CASE 4:  0.664 seconds

pax:~$ ( cat file1 |sed 's/:/: A /' ; cat file2 |sed 's/:/: B /' ) |sort |awk '{
    if (state == 0) {
        before = $5;
        state = 1;
    } else {
        print before" -> "$5" ("("int(100 * $5 / before - 100)"%)")"
        state = 0;
    }
}'
0.004 -> 0.003 (-25%)
0.043 -> 0.040 (-6%)
0.234 -> 0.134 (-42%)
0.564 -> 0.664 (17%)

Here's how it works. The subshell ( ... ) changes both files so they'll sort correctly with a simple sort command into the following:

TEST CASE 1: A   0.004 seconds
TEST CASE 1: B   0.003 seconds
TEST CASE 2: A   0.043 seconds
TEST CASE 2: B   0.040 seconds
TEST CASE 3: A   0.234 seconds
TEST CASE 3: B   0.134 seconds
TEST CASE 4: A   0.564 seconds
TEST CASE 4: B   0.664 seconds

In other words, into pairs of before and after values. The awk then has a mini state machine with two states. In state zero, it simply stores the before time and sets the state to one. In state one, it calculates and prints the required values before setting the state back to zero.


If you want the test case number included and natural sorting, you can use (after adding test case 10 to the input files):

pax:~$ ( cat file1 |sed 's/:/: A /' ; cat file2 |sed 's/:/: B /' ) |sort |awk '{
    if (s == 0) {
        s = 1;
        before = $5;
    } else {
        s = 0;
        printf "%5s %s->%s (%d%%)\n", $3, before, $5, int(100 * $5 / before - 100)
    }
}' |sort -n

   1: 0.004->0.003 (-25%)
   2: 0.043->0.040 (-6%)
   3: 0.234->0.134 (-42%)
   4: 0.564->0.664 (17%)
  10: 0.564->0.764 (35%)

Upvotes: 3

Nikodemus RIP
Nikodemus RIP

Reputation: 1379

It's not exactly what you've asked for, but until someone provides a solution using awk, you're stuck with me and I only know perl :)

#!/usr/bin/perl

use strict;
use warnings;

my $zaehler = 0;

while (<>) {
  /:\s*([\d.]*) s/;
  print(($zaehler/$1)."\n");
  $zaehler = $1;
}

You just give the file as an argument.

Upvotes: 0

Related Questions