I need to grep a file from a line containing Pattern A
to a first empty line.
I used awk
but I don't know how to code this empty line.
cat ${file} | awk '/Pattern A/,/Pattern B/'
sed
might be best:
sed -n '/PATTERN/,/^$/p' file
To avoid printing the empty line:
sed -n '/PATTERN/,/^$/{/^$/d; p}' file
or even better - thanks jthill!:
sed -n '/PATTERN/,/^$/{/./p}' file
Above solutions will give more output than needed if PATTERN
appears more than once. For that, it is best to quit after empty line is found, as jaypal's answer suggests:
sed -n '/PATTERN/,/^$/{/^$/q; p}' file
^$
matches empty lines, because ^
stands for beginning of line and $
for end of line. So that, ^$
means: lines not containing anything in between beginning and end of line./PATTERN/,/^$/{/^$/d; p}
/PATTERN/,/^$/
match lines from PATTERN
to empty line.{/^$/d; p}
remove (d
) the lines being on ^$
format, print (p
) the rest.{/./p}
just prints those lines having at least one character.With awk
you can use:
awk '!NF{f=0} /PATTERN/ {f=1} f' file
Same as sed
, if it has many lines with PATTERN
it would fail. For this, let's exit once empty line is found:
awk 'f && !NF{exit} /PATTERN/ {f=1} f' file
!NF{f=0}
if there are no fields (that is, line is empty), unset the flag f
./PATTERN/ {f=1}
if PATTERN is found, set the flag f
.f
if flag f
is set, this is True, so it performs the default awk behaviour: print the line.$ cat a
aa
bb
hello
aaaaaa
bbb
ttt
$ awk '!NF{f=0} /hello/ {f=1} f' a
hello
aaaaaa
bbb
$ sed -n '/hello/,/^$/{/./p}' a
hello
aaaaaa
bbb
Using sed
:
sed -n '/PATTERN/,/^$/{/^$/q;p;}' file
Using regex
range, you define your range from the PATTERN
to blank line (/^$/
). When you encounter a blank line, you quit else you keep printing.
Using awk
:
awk '/PATTERN/{p=1}/^$/&&p{exit}p' file
You enable a flag when you encounter your PATTERN
. When you reach a blank line and flag is enabled, you exit. If not, you keep printing.
Another alternate suggested by devnull in the comments is to use pcregrep
:
pcregrep -M 'PATTERN(.|\n)*?(?=\n\n)' file
I think this is a nice, readable Perl one-liner:
perl -wne '$f=1 if /Pattern A/; exit if /^\s*$/; print if $f' file
$f
when the pattern is matched Testing it out:
$ cat file
1
2
Pattern A
3
4
5
6
7
8
9
$ perl -wne '$f=1 if /Pattern A/; exit if /^$/; print if $f' file
Pattern A
3
4
5
6
Alternatively, based on the suggestion by @jaypal, you could do this:
perl -lne '/Pattern A/ .. 1 and !/^$/ ? print : exit' file
Rather than using a flag $f
, the range operator ..
takes care of this for you. It evaluates to true when "Pattern A" is found on the line and remains true indefinitely. When it is true, the other part will be evaluated and will print
until a blank line is found.
Never use
/foo/,/bar/
in awk unless you want to get from the first occurrence of "foo" to the last occurrence of "bar" as it makes trivial jobs marginally briefer but even slightly more interesting requirements require a complete re-write.
Just use:
/foo/{f=1} f{print; if (/bar/) f=0}
or similar instead.
In the case the awk solution is:
awk '/pattern/{f=1} f{print; if (!NF) exit}' file
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With