Here's a sed
one that will give you grep
-like behavior across multiple lines:
sed -n '/foo/{:start /bar/!{N;b start};/your_regex/p}' your_file
How it works
-n
suppresses the default behavior of printing every line
/foo/{}
instructs it to match foo
and do what comes inside the squigglies to the matching lines. Replace foo
with the starting part of the pattern.
:start
is a branching label to help us keep looping until we find the end to our regex.
/bar/!{}
will execute what's in the squigglies to the lines that don't match bar
. Replace bar
with the ending part of the pattern.
N
appends the next line to the active buffer (sed
calls this the pattern space)
b start
will unconditionally branch to the start
label we created earlier so as to keep appending the next line as long as the pattern space doesn't contain bar
.
/your_regex/p
prints the pattern space if it matches your_regex
. You should replace your_regex
by the whole expression you want to match across multiple lines.
Two more alternatives :
With awk
awk '{if ($0~"pattern") print $0; nextfile;}' mydir/*
or if your awk
version doesn't support nextfile
(thanks to Stéphane Chazelas for the suggestion) :
awk 'FNR==1{if ($0~"pattern") print $0;}' mydir/*
will read only the first line before switching to next file, and print it only if it matches "pattern"
.
Advantages are that one can fine-tune both the field on which to search the pattern for (using e.g. $2
to search on the second field only) and the output (e.g. $3
to print the third field, or FILENAME
, or even mix).
Note that with the FNR
("current input record number", i.e. line number) version you can fine-tune further the line(s) on which you want to grep : FNR==3
for the third line, FNR<10
for the 10 first lines, etc. (I guess in this case, if you are dealing with very large files and your awk
version supports it you may want to mix FNR
with nextfile
to improve performances.)
With head
, keeping filenames
head -n1 -v mydir/files*|grep -B1 pattern
-v
option of head
will print filenames, and option -B1
of grep
will print the previous line of matching lines — that is, the filenames. If you only need the filenames you can pipe it further to grep
:
head -n1 -v mydir/*|grep -B1 pattern|grep ==>
As noticed by don_crissti in comments, beware of filenames matching the pattern themselves, though…
Best Answer
You can concatenate several paths for grep to look for: