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
  • 2
  • So you want `word3` to trigger `-A 6`, but you want `word1` or `word2` not to trigger `-A 6`; right? I'm afraid you need a more general tool to program this logic, e.g. `awk`. Also note a group separator may appear because of `-A 6`, but not in the output of your first command. To avoid ambiguity you may require `word1` and `word2` to trigger `-A 0`. And if `word3` and `word1` appear in the same line, I guess you still want `-A 6`. Did I guess right? – Kamil Maciorowski Jul 29 '23 at 12:28
  • word1, word2 and word3 are in different lines in the .log file. You are right that i want to see the whole line if word1 or word2 appears. But if word3 is in one line i want to see also this line and the next 6 lines in the common file. – minu Jul 29 '23 at 13:24
  • If you want to add an example then add it to the question ([edit] the question). – Kamil Maciorowski Jul 29 '23 at 13:26
  • thank you for the tip – minu Jul 29 '23 at 13:36
  • Do you have a tip on how to do this with awk? I can now use awk on my computer, but i still have 0 experience with it. I need to read up on it completely. – minu Jul 29 '23 at 19:17

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.

Kamil Maciorowski
  • 69,815
  • 22
  • 136
  • 202