1

/!\ The question is basically solved, see my own answer below for more details and a subsidiary question /!\

I'm trying to add two lines based on specific word, but all I could find is adding everything after some pattern: How to select lines between two marker patterns which may occur multiple times with awk/sed

Which is not what I'm looking after.

Consider the following output:

aji 1
bsk 2
cmq 3
doh 4
enr 5
fwp 6
gzx 7

What I'm trying to get is something like cmq + fwp, which output should be:

9

I do know how to add values, but I'm missing the select line containing cmq, then select line containing fwp part.

So, is there a way awk could strictly select two specific lines independently (then add them) ?

Edit:

As far as I know, matching words is awk '/cmq/', but I need to do that for let's say "fwp" too so I can add them.

X.LINK
  • 133
  • 7
  • 1
    save the value in variable for first match and add it when the second match is found.... – Sundeep Jan 30 '18 at 11:40
  • Is there a way to not use variables ? I'll always have two values. I do however know how to add values, but I'm missing the "select line containing c, then select line containing f" part. – X.LINK Jan 30 '18 at 11:43
  • 1
    @X.LINK, could be there repeated lines (with same letter)? – RomanPerekhrest Jan 30 '18 at 11:51
  • As far as I know, there won't be repeating lines. – X.LINK Jan 30 '18 at 11:52
  • @X.LINK not sure what you mean by that... if you want a way to select two different lines, use alternation or other regex features.. for example, `/cmq|fwp/` – Sundeep Jan 30 '18 at 12:14

2 Answers2

6
$ awk '$1 ~ /^(cmq|fwp)$/{sum+=$2} END { print sum}'  infile

Explanation:

awk '$1 ~ /^(cmq|fwp)$/{     # look for the match in first field
       sum+=$2               # sum up 2nd field ($2) value,where sum is variable
     }
     END{                    # at the end
       print sum             # print variable sum
     }' infile

Test Results:

$ cat infile
aji 1
bsk 2
cmq 3
doh 4
enr 5
fwp 6
gzx 7

$ awk '$1 ~ /^(cmq|fwp)$/{sum+=$2} END { print sum}'  infile
9
Akshay Hegde
  • 16,536
  • 2
  • 22
  • 36
  • Is there a way to strictly and independently search for c then f ? "c" may be "hju" or "kwg" (may not start with "c") and "f" may be "nyo" or "ltm" (may not start with "f"). All I could find for matching word is " awk '/kwg/' ", but I need to do that for let's say "nyo" too so I can add them. – X.LINK Jan 30 '18 at 12:02
  • @X.LINK you can do like this also `awk '$1=="c"{ c = $2 } $2 == "f" {f = $2}END{ print c + f }' infile` – Akshay Hegde Jan 30 '18 at 12:07
  • 3
    You can search for the entire phrases with `awk '/cmq|fwp/ { s += $2 } END { print s}' file` and if you need more, just add more like `/cmq|fwp|nyo|itm/` etc. If you want to restrict to the first field and require the match to be equal to the first field, that would be `awk '$1 ~ /^(cmq|fwp)$/ { ...` – tripleee Jan 30 '18 at 12:37
  • 1
    @triplee : That's what I was searching for, thanks ! So now the almost correct way is: ` awk '/cmq|fwp/ {sum+=$2} END { print sum}' `. The only problem is that sum is still a variable. But I'm afraid there's no way to skip that. – X.LINK Jan 30 '18 at 12:41
  • @tripleee thanks for comment, I hope X.Link is happy now. – Akshay Hegde Jan 30 '18 at 12:42
  • @AkshayHegde: Pretty much, both of you guys answered correctly. Please edit your answer with: " awk '/cmq|fwp/ {sum+=$2} END { print sum}' " so I can mark it as a valid answer. By the way, how do you underline code in comments ? I used ` `, but it didn't worked. – X.LINK Jan 30 '18 at 12:47
  • 1
    @X.LINK modified post, don't use quotes to just use grave accents – Akshay Hegde Jan 30 '18 at 12:54
  • 1
    `print sum+0` to get numeric output even when neither string exists in the input. – Ed Morton Jan 30 '18 at 14:50
0

Now, for a more generic way this time -which even works for subtracting-:

awk '/cmq/{x=$2} /fwp/{y=$2} END {print x+y}'

Where:

awk '          # Invoking awk and its instructions
/cmq/{x=$2}    # Select line with "cmq", then set its value to x. Both must be tied
/fwp/{y=$2}    # Select line with "fwp", then set its value to y. Both must be tied
END            # Ends pattern matching/creation
{print x+y}    # Print the calculated result
'              # Ending awk's instructions

Unfortuanately, two variables are used (x and y).

So, I'm still interested on finding how to do it without any variable, or only one at the very most.

 

I do have a single-variable way for summing:

awk '/cmq|fwp/ {x+=$2} END {print x}'

But doing this for subtracting:

awk '/cmq|fwp/ {x-=$2} END {print x}'

doesn't work.

As an subsidiary question, anyone knows to achieve such subtracting without or with only one variable ?

X.LINK
  • 133
  • 7
  • 1
    probably this : `x=x!=""?x-$2:$2` , will give `-3`, please don't edit again and again on same question, it will be difficult for readers to understand. – Akshay Hegde Jan 30 '18 at 13:53
  • It worked ! However, despite understanding the ternary part, what does ` !="" ` means ? – X.LINK Jan 30 '18 at 14:32
  • 1
    `x!=""` meas if `x` is not equal to null – Akshay Hegde Jan 30 '18 at 14:48
  • 2
    @AkshayHegde Avoid using negatives so you avoid double-negatives creeping in. `x=(x!=""?x-$2:$2)` can be written without a negative as `x=(x==""?$2:x-$2)`. Its also a good idea to always parenthesize your ternary expressions for readability and to avoid syntax errors in some contexts in some awks. – Ed Morton Jan 30 '18 at 14:53
  • 2
    @EdMorton sure, I will note your words, X.link please parenthesize your ternary expressions as Ed suggested above. – Akshay Hegde Jan 30 '18 at 14:55