1

Say I have some files named file1, file2, file3, ... that have the following format

file1

blah blah blah
[PATTERN0]
a10
a20
a30
[PATTERN1]
a11
a21
a31
[PATTERN3]
a13
a13
a33

file 2

blah blah blah
[PATTERN0]
b10
b20
b30
[PATTERN1]
b11
b21
b31
[PATTERN3]
b13
b13
b33

What I would like to do is end up with a file that contains the sum of each individual entry for all files after the specific pattern (i.e. PATTERN0). For instance the file should have

a10+b10
a20+b20
a30+b30

So far I can only rrad and print the values using

awk '/PATTERN0/ {for(i=1; i<=3; i++) {getline;print $1}}' file*

Any idea how to do it?

5
  • 1
    may be concatenate the input files column wise using paste and then use awk?
    – Sundeep
    Mar 27, 2017 at 15:41
  • @Sundeep : Thank you for your comment! I don't know what do you mean :( I am a bit familiar with paste in awk but I can't make the connection on how to use paste first, unless you are referring to something else.
    – Thanos
    Mar 27, 2017 at 15:44
  • I meant like paste file* > combined.txt so that each line of the files get combined in single line separated by a delimiter (tab by default)... then you read that file and use awk.. but seems you have a simple awk alone solution :)
    – Sundeep
    Mar 27, 2017 at 15:53
  • @Sundeep : I really like the idea with paste! I will try to find a way! Is it possible to post an answer with that?
    – Thanos
    Mar 27, 2017 at 15:57
  • Give us usable sample input files: stackoverflow.com/help/mcve Mar 27, 2017 at 17:17

2 Answers 2

4

With awk, assuming you always have at least two files, that all files have the same number of lines between [PATTERN0] and [PATTERN1], and that said lines are actually numbers:

awk '
    BEGIN {
        # discard the garbage before [PATTERN0]
        for (i = 1; i < ARGC; i++) {
            do      
                getline str <ARGV[i]
            while (str !~ /\[PATTERN0\]/)
        }

        # read sum from first file, then add numbers in turn from the other files
        while ((getline sum <ARGV[1]) && sum !~ /\[PATTERN1\]/) {
            for (i = 2; i < ARGC; i++) {
                getline nr <ARGV[i]
                sum += nr
            }
            print sum
        }
    }' file1 file2 file3 ...
6
  • Thanks for your answer! I created a script called script.awk and I am running it using awk -f script.awk but I get the following error awk -f script.awk awk: script.awk:1: awk ' awk: script.awk:1: ^ invalid char ''' in expression awk: script.awk:1: awk ' awk: script.awk:1: ^ syntax error
    – Thanos
    Mar 27, 2017 at 15:54
  • @Thanos My script doesn't contain character '. shrug Mar 27, 2017 at 15:56
  • @SatKatsura : I am not I understand what you mean...
    – Thanos
    Mar 27, 2017 at 15:58
  • @Thanos You made an error when pasting my script. Mar 27, 2017 at 15:59
  • 1
    What you need to put in script.awk is the string between awk ' and ' file1 .... The ' are not part of the script. Mar 27, 2017 at 16:02
0

A combination of paste + awk gives nice results:

$ paste -d"+" file1 file2 |awk -F"[+]" '/PATTERN/{print $1;next}1'

I call awk to avoid having [PATTERN0]+[PATTERN0] - you can either remove it or if you don't want [PATTERN] to be printed at all change last awk to
...|awk -F"[+]" '/PATTERN/{next}1

Testing:

$ paste -d"+" <(echo "$a") <(echo "$b") |awk -F"[+]" '/PATTERN/{next}1'
a10+b10
a20+b20
a30+b30
a11+b11
a21+b21
a31+b31
a13+b13
a13+b13
a33+b33

Also here is an easy awk solution:

$ awk -v RS="[PATTERN[0-9]+]" '{for (i=1;i<=NF;i++) (NR==FNR)?a[RT][i]=$i:a[RT][i]=a[RT][i] "+" $i} \
END{for (k in a) for (l in a[k]) print a[k][l]}' <(echo "$a") <(echo "$b")

PS: Above awk is in one-line by removing the \. It is split in two lines just for readability here.

Pitfall for this awk is that at END section, printing is correct but in random PATTERN order (i.e [PATTERN3] data might be printed first instead of [PATTERN0]) due to the way that awk prints arrays with this for method.

1

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .