3

I have a file with lines such as:

....
pattern1 100 200 300
pattern2 300 400 400
pattern1 300 900 700
pattern1 200 500 900
...

As shown in the above example, there are some lines where pattern2 follows pattern1 but not all. I would like to match pattern1 then check if the next line has pattern2 and if it does, alter the next number field by multiplying it with a constant factor. I tried using getline with awk but it erases the lines with pattern1 from the resulting output:

awk '/pattern1/{getline; if($1==pattern2) $(NF-2)*=0.889848406214}1' infile.dat

Any suggestions how can I accomplish this without altering anything else in the input file.

2
  • How big are your files? Are you open to solutions that would load the entire file into memory? Are you open to non-awk solutions? Are there more than two patterns? Can you have pattern45 as well?
    – terdon
    Jan 28, 2016 at 16:57
  • Files are medium sized, nothing too big. However, I would prefer awk solution because there is other processing done on the file which is done via awk.
    – Ketan
    Jan 28, 2016 at 19:37

2 Answers 2

4
awk '
  /pattern1/ { f = 1; print; next }
  f && /pattern2/ { $(NF-2) *= 0.889848406214 }
  { f = 0; print }
' <file
3
  • 1
    /pattern2/&&f{$(NF-2)*=0.889848406214}{print;f=0}/pattern1/{f=1}
    – Costas
    Jan 28, 2016 at 17:41
  • @Costas: Cool, a little shorter.
    – cuonglm
    Jan 28, 2016 at 17:49
  • 1
    Can you explain each line please? May 23, 2020 at 16:52
4

Your approach is failing because getline immediately moves to the next line so the current one is lost. A simple solution would be to save the current line in a variable and then move to the next:

$ awk '{
        if(/pattern1/){
            l=$0; 
            getline; 
            if($1=="pattern2"){
                $(NF-2)*=0.889848406214
            } 
            print l"\n"$0
        }
        else{print}
       }' file
pattern1 100 200 300
pattern2 266.955 400 400
pattern1 300 900 700
pattern1 200 500 900

Alternatively, use a flag that keeps track of whether the previous line matched pattern1:

$ awk '{if(/pattern2/ && l){$(NF-2)*=0.889848406214} /pattern1/ ? l=1 : l=0;}1;' file
pattern1 100 200 300
pattern2 266.955 400 400
pattern1 300 900 700
pattern1 200 500 900

You must log in to answer this question.

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