0

I need to match a pattern in a file AND print the following 2 lines. I am using grep -A2 for this. But I want to ignore some lines from this first grep.

I need the output from the first 'grep -A2' to do some further processing on so piping to grep -v won't help me as far as I understand.

$cat file.txt
stringA-hurdygurdy-andmorechars
line1
line2
stringA-hurdygurdy-stringB-andmorechars
line1
line2
stringA-hurdygurdy-andmorechars
line1
line2

I need to grep -A2 all the lines that have "stringA-hurdygurdy" but not the ones that contain stringB.

I'm trying grep -A2 ^stringA.*[^stringB].* file.txt

anubhava
  • 761,203
  • 64
  • 569
  • 643
Jay
  • 456
  • 4
  • 11
  • 2
    Dupes are not correct as given `grep` solutions won't work with non-gnu awk as `-A2` is being used. An `awk` would be better solution that `grep` here. – anubhava Nov 18 '20 at 15:22
  • Please add your desired output (no description) for that sample input to your question (no comment). – Cyrus Nov 18 '20 at 19:03

5 Answers5

2

You can do it using awk:

awk '/stringA/ && !/stringB/ {n = NR+2} n >= NR' file.txt

stringA-hurdygurdy-andmorechars
line1
line2
stringA-hurdygurdy-andmorechars
line1
line2
anubhava
  • 761,203
  • 64
  • 569
  • 643
1

Could you please try following, written and tested with shown samples in GNU awk. There is a variable named lines where we could put how many lines we need to print after matched pattern.

awk -v lines="2" '
/^stringA/ && !/stringB/{
  count=0
  found=1
  print
  next
}
found && ++count<=lines
'  Input_file

Explanation: Adding detailed explanation for above.

awk -v lines="2" '           ##Starting awk program from here and setting lines variabnle value to 2.
/^stringA/ && !/stringB/{    ##Checking condition if line contains stringA and DOES NOT contain stringB then do following.
  count=0                    ##Setting count variable to 0 here.
  found=1                    ##Setting found variable to 1 here.
  print                      ##Printing current line here.
  next                       ##next will skip statements from here.
}
found && ++count<=lines      ##Checking condition if found is SET and count(with increasing value of 1) is lesser than lines then print that line.
' Input_file                 ##Mentioning Input_file name here.
RavinderSingh13
  • 130,504
  • 14
  • 57
  • 93
0

With grep -P you need a negative lookahead:

^stringA(?!.*stringB).*$[\r\n]+.*[\r\n]+.*
MonkeyZeus
  • 20,375
  • 4
  • 36
  • 77
  • But what if `stringB` is before `stringA`? I prefere capturing the full line and made a positive lookbehind and a negative lookbehind. – rittergig Nov 18 '20 at 13:56
  • @rittergig Ask OP. Per their `^stringA` I am assuming they are interested in lines that start with `stringA` – MonkeyZeus Nov 18 '20 at 13:56
  • @rittergig If you're interested then `^(?=.*stringA)(?!.*stringB).*$` would achieve that. – MonkeyZeus Nov 18 '20 at 13:59
0

Use this Perl one-liner (similar to the awk solution from anubhava):

perl -lne '$line_num = $. if /stringA/ && !/stringB/; print if $line_num <= $. && $. <= ( $line_num + 2 );' file.txt

Output:

stringA-hurdygurdy-andmorechars
line1
line2
stringA-hurdygurdy-andmorechars
line1
line2

The Perl one-liner uses these command line flags:
-e : Tells Perl to look for code in-line, instead of in a file.
-n : Loop over the input one line at a time, assigning it to $_ by default.
-l : Strip the input line separator ("\n" on *NIX by default) before executing the code in-line, and append it when printing. Its use in this particular case as posted by the OP is optional.

$. : current input line number.

SEE ALSO:
perldoc perlrun: how to execute the Perl interpreter: command line switches
perldoc perlvar: Perl predefined variables

Timur Shtatland
  • 12,024
  • 2
  • 30
  • 47
-1

I don't know the grep syntax but here is the regex which worked for me (.NET regex engine):
^.*$(?<=stringA.*)(?<!stringB.*)

You capture a complete line, then you made two look-behinds.

I had to enable the multiline option /m.

Test it in .NET:

Regex newRegex = new Regex(
    @"^.*$(?<=stringA.*)(?<!stringB.*)",
    RegexOptions.Multiline
);
rittergig
  • 715
  • 1
  • 5
  • 16