0

I've the input files with fields separated with colon:

main:

one:111:222:333
fiv:333:222:333
two:123:234:500

file1:

one:111:222:333
two:123:234:501

file2:

one:111:222:333
thr:-:234:232
fiv:999:500:232

Thanks to hints on link I have a bit modified awk code:

$ awk -F':' -vf=main 'FILENAME==f{m=$0};FILENAME!=f&&$2~/[0-9]+/{if ($2~/[0-9]+/&&(!($1 in a) || $3 > a[$1])) { a[$1] = $3; b[$1] = $0 } next;}{if (($1 in a) && (a[$1] > $3)){ print b[$1]":updated:"m; delete b[$1] } else print; }' file* main
thr:-:234:232
one:111:222:333
fiv:999:500:232:updated:fiv:333:222:333
two:123:234:500

Why it prints also line thr:-:234:232? As thr does not occur in main file, it should be ignored for any update in it. Updated should be only these lines basing on 1st column, which exists in main file and corresponding lines with 1st column exist in file1 or file2 and have bigger value in 3rd column.

Why $2~/[0-9]+/ does not work here?

Update: It still did not figured it out, please have a look:

when I modify test main file to:

one:111:222:333 fiv:333:222:333 two:123:234:500 ten.233:422:452

And run this awk command:

$ awk -F':' -vf=main 'FILENAME==f{m=$0};FILENAME!=f&&$2~/[0-9]+/{if ($2~/[0-9]+/&&(!($1 in a) || $3 > a[$1])) { a[$1] = $3; b[$1] = $0 } next;}{if (($1 in a) && (a[$1] > $3)){ print b[$1]":updated:"m; delete b[$1] } else print; }' file* main
thr:-:234:232
one:111:222:333
fiv:999:500:232:updated:fiv:333:222:333
two:123:234:500
ten.233:422:452

So output is wrong because of thr line which should not be on output as thr is not in main file

I modified command adding additional condition else if($1 in a) {print}; but then it does not print line beginning with "ten" in main file:

$ awk -F':' -vf=main 'FILENAME==f{m=$0};FILENAME!=f&&$2~/[0-9]+/{if ($2~/[0-9]+/&&(!($1 in a) || $3 > a[$1])) { a[$1] = $3; b[$1] = $0 } next;}{if (($1 in a) && (a[$1] > $3)){ print b[$1]":updated:"m; delete b[$1] } else if($1 in a) {print}; }' file* main
one:111:222:333
fiv:999:500:232:updated:fiv:333:222:333
two:123:234:500

I'll appreciate any help very much.

Awk is really very awesome, unfortunately I being not a programmer can't figure it out on my own yet.

  • 3
    That is a gnarly one-liner. Whitespace is free you know – glenn jackman Apr 14 '18 at 0:10
3

Because you have next in the block with condition FILENAME != f && $2 ~ /[0-9]+/. That thr line does not meet that condition, so it falls into the "every line" block. There, $1 is not in a so the else block is entered and the line is printed.

I'm sure you would have been able to figure this out yourself if you just used sensible indentation so you actually see your program:

awk -F':' -vf=main '
    FILENAME == f {m = $0}
    FILENAME != f && $2 ~ /[0-9]+/ {
        if ($2 ~ /[0-9]+/ && (!($1 in a) || $3 > a[$1])) { 
            a[$1] = $3
            b[$1] = $0 
        } 
        next
    }
    {
        if (($1 in a) && (a[$1] > $3)) { 
            print b[$1]":updated:"m
            delete b[$1] 
        } else 
            print
    }
' file* main
  • I am not sure how to add the condition to ignore such line, so ignore lines of file{1,2} having $1 value which is not occuring in main's $1 – DonJ Apr 14 '18 at 7:56
  • probably I have figured it out, I additional if at the end else if ($1 in a){ print }; }' I am not a programmer, usually works only with HW and some bash scripting, I will appreciate someone explain the a in the code which is black magic for me, it represents main files entries or any file? where/when it was "established"? – DonJ Apr 14 '18 at 11:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.