ChatGPT解决这个技术问题 Extra ChatGPT

Negative matching using grep (match lines that do not contain foo)

I have been trying to work out the syntax for this command:

grep ! error_log | find /home/foo/public_html/ -mmin -60

OR:

grep '[^error_log]' | find /home/baumerf/public_html/ -mmin -60

I need to see all files that have been modified except for those named error_log.

I've read about it here, but only found one not-regex pattern.

[^error_log] would never ever work anyway, [] are char classes, regexp 's in general are not good at negative patterns (unless the engine implements negative lookaheads).

f
fedorqui

grep -v is your friend:

grep --help | grep invert  

-v, --invert-match select non-matching lines

Also check out the related -L (the complement of -l).

-L, --files-without-match only print FILE names containing no match


Worth mentioning that for multiple (negative) matches -e option can be used: grep -v -e 'negphrase1' -e 'negphrase2'
Similar to the comment from @Babken-Vardanyan Also - able to use pipes to join multiple matches e.g. grep -v 'negphrase1|negphrase2|negphrase3'
Last comment is NOT the same as it will search for things that don't match both rather than either. ie If it matches one but not the other its still printed. Try it both ways with non-similar strings
@EvanLanglois - forcing grep to interpret the pattern as an extended regular expression using -E works, i.e. grep -vE 'negphrase1|negphrase2|negphrase3'
@OlleHärstedt, I think I misunderstood your scenario in my previous comment, the following may be what you're looking for grep "" /dev/null * | grep foo | grep -v bar | cut -d: -f1 | sort -u (why the first grep?, there's always a way :))
L
L0j1k

You can also use awk for these purposes, since it allows you to perform more complex checks in a clearer way:

Lines not containing foo:

awk '!/foo/'

Lines containing neither foo nor bar:

awk '!/foo/ && !/bar/'

Lines containing neither foo nor bar which contain either foo2 or bar2:

awk '!/foo/ && !/bar/ && (/foo2/ || /bar2/)'

And so on.


That's actually quite cool. You don't even have to learn the complete awk language in order to group regexp with logical operators. Thanks for this answer!
The OP specifically asks for grep. Why is this upvoted?
P
Papa Smurf

In your case, you presumably don't want to use grep, but add instead a negative clause to the find command, e.g.

find /home/baumerf/public_html/ -mmin -60 -not -name error_log

If you want to include wildcards in the name, you'll have to escape them, e.g. to exclude files with suffix .log:

find /home/baumerf/public_html/ -mmin -60 -not -name \*.log

while one is going to use mmin to search for files modified within 60 mins, use -type f too as mentioned here stackoverflow.com/a/33410471/2361131