tags:

views:

209

answers:

6

I want to find files that have "abc" AND "efg" in that order, and those two strings are on different lines in that file. Eg: a file with content:

blah blah..
blah blah..
blah abc blah
blah blah..
blah blah..
blah blah..
blah efg blah blah
blah blah..
blah blah..

Should be matched.

+1  A: 

I don't know how I would do that with grep, but I would do something like this with awk:

awk '/abc/{ln1=NR} /efg/{ln2=NR} END{if(ln1 && ln2 && ln1 < ln2){print "found"}else{print "not found"}}' foo

You need to be careful how you do this, though. Do you want the regex to match the substring or the entire word? add \w tags as appropriate. Also, while this strictly conforms to how you stated the example, it doesn't quite work when abc appears a second time after efg. If you want to handle that, add an if as appropriate in the /abc/ case etc.

frankc
+2  A: 

Sadly, you can't. From the grep docs:

grep searches the named input FILEs (or standard input if no files are named, or if a single hyphen-minus (-) is given as file name) for lines containing a match to the given PATTERN.

Kaleb Pederson
A: 

You can do that very easily if you can use Perl.

perl -ne '$abc = 1 if (/abc/); $efg = 1 if (/efg/); END { if ($abc && $efg) { print "Found in $ARGV\n"; }  }' yourfilename.txt

You can do that with a single regular expression too, but that involves taking the entire contents of the file into a single string, which might end up taking up too much memory with large files. For completeness, here is that method:

perl -e '@lines = <>; $content = join("", @lines); print "Found in $ARGV\n" if ($content =~ /abc.*efg/s);' yourfilename.txt
sundar
+2  A: 

I'm not sure if it is possible with grep. But sed makes it very easy:

sed -e '/abc/,/efg/!d' [file-with-content]

LJ
+1 neat! will work in all Unix(s)
ring bearer
+3  A: 

Grep is not sufficient for this operation.

pcregrep which is found in most of the modern Linux systems can be used as

pcregrep -M  'abc.*(\n|.)*efg' test.txt
ring bearer
A: 
#!/bin/bash
shopt -s nullglob
for file in *
do
 r=$(awk '/abc/{f=1}/efg/{g=1;exit}END{print g&&f ?1:0}' file)
 if [ "$r" -eq 1 ];then
   echo "Found pattern in $file"
 else
   echo "not found"
 fi
done
ghostdog74