0

I am using the windows version of grep "GNU Grep".

syntax: grep [OPTIONS] PATTERN [FILE...]

How can I combine different options with different patterns?

Both lines listed here work on their own. But I have not yet succeeded in combining them.

grep -i -a -h -E "word1|word2" INfilename.log* > "OUTfilename.txt"
grep -i -a -h -A 6 "word3" INfilename.log* > "OUTfilename.txt"

Example input:

2023-07-29 11:31:01 bla something bla
2023-07-29 11:31:02 bla word1 bla
2023-07-29 11:31:03 bla something bla
2023-07-29 11:31:04 bla word2 bla
2023-07-29 11:31:05 bla something bla
2023-07-29 11:31:06 bla word3 bla
2023-07-29 11:31:07 bla something bla
2023-07-29 11:31:08 bla something bla
2023-07-29 11:31:09 bla something bla
2023-07-29 11:31:10 bla something bla
2023-07-29 11:31:11 bla something bla
2023-07-29 11:31:12 bla something bla
2023-07-29 11:31:13 bla something bla

The result should look like:

2023-07-29 11:31:02 bla word1 bla
2023-07-29 11:31:04 bla word2 bla
2023-07-29 11:31:06 bla word3 bla
2023-07-29 11:31:07 bla something bla
2023-07-29 11:31:08 bla something bla
2023-07-29 11:31:09 bla something bla
2023-07-29 11:31:10 bla something bla
2023-07-29 11:31:11 bla something bla
2023-07-29 11:31:12 bla something bla
minu
  • 3

1 Answers1

0

I don't think you can do this with grep. -A is a global option and there is no way to apply it to a subset of patterns. You need a more general tool to program the logic you want.

The following awk code works well with your example:

#!/bin/awk -f
FNR==1 { n=-1 }
/word1|word2/ && n<0 { n=0 }
/word3/       && n<6 { n=6 }
n>=0 { n--; print }

Notes:

  • I'm a Linux guy and I don't use Windows. The code is a script for Linux. If you can run awk in Windows, you should at least be able to run the code by saving it in a file and invoking awk -f path_to_the_file. I guess this command will also work:

    awk "FNR==1 { n=-1 } /word1|word2/ && n<0 { n=0 } /word3/ && n<6 { n=6 } n>=0 { n--; print }"
    
  • The script (or the command) can be invoked with one or more pathnames as additional arguments to specify files to read the input from; so this should be possible:

    awk … INfilename.log*
    

    (at least it works in Linux). Note when our code proceeds to the next file, n is deliberately reset, so the behavior mimicking grep's -A 6 triggered by word3 near the end of one file does not extend to the next file. If you want to treat the content of many files as one stream, concatenate the files first (in Linux: cat … | awk …).

  • You can easily add more regular expressions with their own values of n, e.g. /word4/ && n<3 { n=3 }. Note the value you would use with grep's -A (here 3) appears in two places; I chose KISS over DRY.

  • If a line matches more than one pattern then the biggest n will win.

  • A matching line inside what man grep calls "trailing context" can only make the context longer, never shorter. In other words, if you imagine files as ordered sets of lines, from our code you will get the union of all matching lines and trailing contexts.

  • grep -A may print group separators. Your example does not contain any, therefore our awk code does not bother.

  • Pattern matching in our code is case-sensitive. I notice you used grep -i. See this answer and adjust the code if needed (replace /word1|word2/ with tolower($0) ~ /word1|word2/ etc.). Note you can adjust or not for each pattern independently.