LebGeeks

A community for technology geeks in Lebanon.

You are not logged in.

#1 February 1 2015

hussam
Member

grep question

I am trying to find files containing certain strings.
I can do
find -type f -exec grep string {} \;

But in this case, I want to find all files containing "string1: anything" but not the ones containing "string1: string2"

find . -type f -exec grep -q "string1:" {} \; -exec grep -v "string1: string2" {} \; 

is returning files containing "string1: string2" which is the opposite of what I want.

so I tried

grep -r "string1:" ./ | grep -v "string1: string2"

but that is still listing files containing "string1: string2"
Any ideas?

Last edited by hussam (February 1 2015)

Offline

#2 February 1 2015

rolf
Member

Re: grep question

I think you have to use negative lookaheads in grep. I use grep with the perl syntax. Not sure about the bash syntax so you'll have to look it up.

Offline

#3 February 1 2015

hussam
Member

Re: grep question

I'll try:

 grep -rL "string1: string2" | xargs grep "string1"

Offline

#4 February 1 2015

Ra8
Member

Re: grep question

Try this:

find . -type f | grep "string1." | grep -v "string1.string2"

Offline

#5 February 2 2015

Joe
Member

Re: grep question

@hussam:

First, you don't need to use `find`, since you can use `grep -r` which will traverse directories recursively.[1]

Second, your question is asking to list files containing patterns, but the commands you run are actually listing pattern matches, not filenames.

If you want to list the name of the files matching your pattern, you have to use these options:

man grep(1) wrote:

       -L, --files-without-match
          Suppress normal output; instead print the     name  of  each     input
          file from which no output would normally have been printed.  The
          scanning will stop on the first match.

       -l, --files-with-matches
          Suppress normal output; instead print the     name  of  each     input
          file  from  which     output would normally have been printed.  The
          scanning will stop on the first match.

In your case, try something like this:

grep -rl 'string1:' . | xargs grep -L 'string1: string2'

It's pretty close to your suggestion, but arguably a bit faster,  if the second grep is running on a considerably smaller subset (which is highly likely).

[1]: About traversing directories recursively, you can also get by using shell features. If you're using a modern shell (like zsh or bash 4), you can use the really cool recursive globbing feature. (Note that by default, OS X uses bash 3, which is political and idiotic, but that's a rant for another day...). Anyway, my point is that you should avoid Useless Uses of Find. A good rule of thumb is, every time you use `find .`, there's probably a better way to do it.

Offline

#6 February 2 2015

Joe
Member

Re: grep question

Following up on rolf's suggestion, I tried to achieve this using lookaheads. Unfortunately, I only found how to do this using GNU grep (which is available on most linux distros, but not other unices). GNU grep has a `-P` option that supports Perl compatible regex (pcre).

You can try doing something like this:

grep -Prl 'string1:(?! string2)' .

It would probably be better on a large amount of files searched, however this comes with a warning.

man (gnu) grep(1) wrote:

      -P, --perl-regexp
              Interpret PATTERN as a Perl regular expression.  This is highly experimental and grep -P may warn of unimplemented features.

Offline

#7 February 3 2015

hussam
Member

Re: grep question

 grep -rL "string1: string2" | xargs grep "string1"

did it. It excludes "string1: string2" but matches "string1: anything else".

Joe, it's the content of the files and not their names.

I will try your suggestion

grep -Prl 'string1:(?! string2)' .

next time I need to run this. Thank you.

Last edited by hussam (February 3 2015)

Offline

#8 February 3 2015

Joe
Member

Re: grep question

Wait, @hussam. Your first (second) attempt should've worked:

grep -r "string1:" ./ | grep -v "string1: string2"

Are you sure it didn't? In that case, would it be possible to show me the actual files and patterns that made it trip? I'm genuinely curious. (Hopefully it's not private/sensitive info).

I will try your suggestion
grep -Prl 'string1:(?! string2)' .
next time I need to run this. Thank you.

Obviously, beware of removing `-l` if you want to see the content and not the filename.

Offline

#9 February 3 2015

hussam
Member

Re: grep question

I wanted to list the file name but match content.

Offline

Board footer