Can grep output only specified groupings that match?
GNU grep has the -P
option for perl-style regexes, and the -o
option to print only what matches the pattern. These can be combined using look-around assertions (described under Extended Patterns in the perlre manpage) to remove part of the grep pattern from what is determined to have matched for the purposes of -o
.
$ grep -oP 'foobar \K\w+' test.txt
bash
happy
$
The \K
is the short-form (and more efficient form) of (?<=pattern)
which you use as a zero-width look-behind assertion before the text you want to output. (?=pattern)
can be used as a zero-width look-ahead assertion after the text you want to output.
For instance, if you wanted to match the word between foo
and bar
, you could use:
$ grep -oP 'foo \K\w+(?= bar)' test.txt
or (for symmetry)
$ grep -oP '(?<=foo )\w+(?= bar)' test.txt
sed -n "s/^.*foobar\s*\(\S*\).*$/\1/p"
-n suppress printing
s substitute
^.* anything before foobar
foobar initial search match
\s* any white space character (space)
\( start capture group
\S* capture any non-white space character (word)
\) end capture group
.*$ anything after the capture group
\1 substitute everything with the 1st capture group
p print it
Standard grep can't do this, but recent versions of GNU grep can. You can turn to sed, awk or perl. Here are a few examples that do what you want on your sample input; they behave slightly differently in corner cases.
Replace foobar word other stuff
by word
, print only if a replacement is done.
sed -n -e 's/^foobar \([[:alnum:]]\+\).*/\1/p'
If the first word is foobar
, print the second word.
awk '$1 == "foobar" {print $2}'
Strip foobar
if it's the first word, and skip the line otherwise; then strip everything after the first whitespace and print.
perl -lne 's/^foobar\s+// or next; s/\s.*//; print'