I am passing a list of regex patterns to grep
to check against a syslog file. They are usually matching an IP address and log entry;
grep "1\.2\.3\.4.*Has exploded" syslog.log
It's just a list of patterns like the "1\.2\.3\.4.*Has exploded"
part I am passing, in a loop, so I can't pass "-v" for example.
I am confused trying to do the inverse of the above, and NOT match lines with a certain IP address and error so "!1.2.3.4.*Has exploded" will match syslog lines for anything other than 1.2.3.4 telling me it has exploded. I must be able to include an IP to NOT match.
I have seen various similar posts on StackOverflow. However they use regex patterns that I can't seem to get to work with grep
. Can anyone provide a working example for grep
please?
UPDATE: This is happening in a script like this;
patterns[1]="1\.2\.3\.4.*Has exploded"
patterns[2]="5\.6\.7\.8.*Has died"
patterns[3]="\!9\.10\.11\.12.*Has exploded"
for i in {1..3}
do
grep "${patterns[$i]}" logfile.log
done
patterns[3]="\!9\.10\.11\.12.*Has exploded"
changes to patterns[3]="(?<!9\.10\.11\.12).*Has exploded"
and grep "${patterns[$i]}" logfile.log
changes to grep -P "${patterns[$i]}" logfile.log
PCRE assumes more metacharacters by default, so some of the escapes may need to be removed from other matching expressions.
grep
matches, grep -v
does the inverse. If you need to "match A but not B" you usually use pipes:
grep "${PATT}" file | grep -v "${NOTPATT}"
(?<!1\.2\.3\.4).*Has exploded
You need to run this with -P to have negative lookbehind (Perl regular expression), so the command is:
grep -P '(?<!1\.2\.3\.4).*Has exploded' test.log
Try this. It uses negative lookbehind to ignore the line if it is preceeded by 1.2.3.4
. Hope that helps!
grep
doesn't support lookaround. Unless you're using Gnu grep
and use the --P
parameter to make it use a PCRE engine.
grep -P '(?<!1\.2\.3\.4) Has exploded' test.log
Note that the lookbehind only works on the characters immediately preceding the matching part of the expression, so if there's other things between the address and message, e.g. 1.2.3.4 FOO Has exploded
, this won't work.
.*
after the negative lookbehind since his example also has it, I imagine there might be other text in between.
patterns[1]="1\.2\.3\.4.*Has exploded"
patterns[2]="5\.6\.7\.8.*Has died"
patterns[3]="\!9\.10\.11\.12.*Has exploded"
for i in {1..3}
do
grep "${patterns[$i]}" logfile.log
done
should be the the same as
egrep "(1\.2\.3\.4.*Has exploded|5\.6\.7\.8.*Has died)" logfile.log | egrep -v "9\.10\.11\.12.*Has exploded"
It seems no one has posted a blend of the best of all answers, regex (-E
) with match inversion (-v
)
grep -Ev 'pattern1|pattern2|pattern3' file
Notably, no lookarounds required, so this works if your grep version doesn't have -P
available.
Success story sharing
-v
and you can use it in a loop. Perhaps you need to be more specific about your limitations, or perhaps you have a misconception about how your script should work. Try posting some code.