2

I am trying to delete all lines with a specific pattern (PATTERN 2) only when the previous line has another specific pattern (PATTERN 1).

The code looks like this:

PATTERN 1
PATTERN 2   <- This line should be deleted
NNN
PATTERN 2
PATTERN 1
PATTERN 2   <- This line should be deleted
blabla
PATTERN 1
blabla
PATTERN 2
PATTERN 1
PATTERN 2   <- This line should be deleted

PATTERN 2 should be deleted ONLY when the previous line is PATTERN 1

  • I know how to delete all lines with PATTERN 2 : sed '/PATTERN 2/d'
  • and I can delete all lines that follow PATTERN 1: sed '/PATTERN 1/{n;N;d}'

However, I don't know to apply both requirements to a single AWK or SED.

How can this be done with AWK? Thank you in advance,

Kspael
  • 177
  • 6
  • Never use the word "pattern" when talking about matching text as it's ambiguous. Please read https://stackoverflow.com/questions/65621325/how-do-i-find-the-text-that-matches-a-pattern to understand the issue and then replace "pattern" with string-or-regexp and full-or-partial everywhere it occurs in your question. – Ed Morton Sep 26 '21 at 12:01

4 Answers4

3

Assuming by "PATTERN" you mean "partial regexp match" since that's what you use in the sed scripts in your question:

$ awk '!(/PATTERN 2/ && prev~/PATTERN 1/); {prev=$0}' file
PATTERN 1
NNN
PATTERN 2
PATTERN 1
blabla
PATTERN 1
blabla
PATTERN 2
PATTERN 1
Ed Morton
  • 188,023
  • 17
  • 78
  • 185
1
Mac_3.2.57$cat input | awk '{if(lastline!="PATTERN 1"||$0!="PATTERN 2"){print}};{lastline=$0}'
PATTERN 1
NNN
PATTERN 2
PATTERN 1
blabla
PATTERN 1
blabla
PATTERN 2
PATTERN 1
Mac_3.2.57$cat input 
PATTERN 1
PATTERN 2
NNN
PATTERN 2
PATTERN 1
PATTERN 2
blabla
PATTERN 1
blabla
PATTERN 2
PATTERN 1
PATTERN 2
Mac_3.2.57$
user3439894
  • 7,266
  • 3
  • 17
  • 28
Andrew
  • 1
  • 4
  • 19
  • Thanks! I just tried but it is printing everything (it is not removing the second pattern when the first pattern is on the previous line). – Kspael Sep 26 '21 at 02:58
  • you can see it worked for me, right? please post your code, run, and input. – Andrew Sep 26 '21 at 03:17
  • Thanks Andrew. I have done the test on my Mac and it's working indeed ... but it's not on WSL. Probably an issue with my computer. I will look into it. `$ cat t.txt | awk '{if(lastline!="PATTERN 1"||$0=!"PATTERN 2"){print}};{lastime=$0}'` `PATTERN 1 PATTERN 2 NNN PATTERN 2 PATTERN 1 PATTERN 2 blabla PATTERN 1 blabla PATTERN 2 PATTERN 1 PATTERN 2` `$ cat t.txt` `PATTERN 1 PATTERN 2 NNN PATTERN 2 PATTERN 1 PATTERN 2 blabla PATTERN 1 blabla PATTERN 2 PATTERN 1 PATTERN 2` – Kspael Sep 26 '21 at 04:34
1

With your shown samples/attempts, please try following awk code.

awk '/PATTERN 1/{found=1;print;next} found && /PATTERN 2/{found="";next} 1' Input_file

Explanation: Adding detailed explanation for above.

awk '                   ##Starting awk program from here.
/PATTERN 1/{            ##Checking if line contains PATTERN 1 then do following.
  found=1               ##Setting found to 1 here.
  print                 ##printing current line here.
  next                  ##next will skip all further statements from here.
}
found && /PATTERN 2/{   ##Checking condition if found is NOT NULL AND PATTERN 2 is found.
  found=""              ##Nullifying found here.
  next                  ##next will skip all further statements from here.
}
1                       ##printing current line here.
' Input_file            ##Mentioning Input_file name here.
RavinderSingh13
  • 130,504
  • 14
  • 57
  • 93
  • Thank you so much for the reponse and for the detailed explanation! I just did a test however one additional PATTERN 2 was removed (line 10 on the source code: https://ideone.com/d2oZBR). This line should not removed as the previous line is not PATTERN 1. – Kspael Sep 26 '21 at 04:58
  • @Pierre, Your welcome, how about trying `awk '/PATTERN 1/{found=1;print;next} found && ++count==1{if($0~/PATTERN 2/){next};count=found=""} 1' Input_file` once? Let me know how it goes? – RavinderSingh13 Sep 26 '21 at 05:14
1

Another variation could be checking if the current line matches PATTERN 2 and the last line matches PATTERN 1.

If that is the case, print the current line, else move to the next line without printing it.

awk '{if(/PATTERN 2/&&last~/PATTERN 1/){last=$0;next}last=$0}1' file

See an awk demo.

In a more readable format:

awk '
{
  if (/PATTERN 2/ && last ~ /PATTERN 1/) {   # If both patterns match
    last = $0                                # Save the last line, but don't print
    next                                     # Go on to the next record
  }
  last = $0                                  # Save the last line
}1                                           # Print the line
' file
The fourth bird
  • 154,723
  • 16
  • 55
  • 70