Can GNU Grep output a selected group?

48

12

Is it possible to use GNU grep to get a matched group from an expression?

Example:

echo "foo 'bar'" | grep -oE "'([^']+)'"

Which would output "'bar'". But I would like to get just "bar", without having to send it through grep one more time (ie. get the matched group). Is that possible?

Torandi

Posted 2009-07-22T23:26:04.717

Reputation: 768

Answers

50

You can use sed for this. On BSD sed:

echo "foo 'bar'" | sed -E "s/.*'([^']+)'.*/\\1/"

Or, without the -E option:

sed "s/.*'\([^']\+\)'.*/\1/"

This doesn't work for multiline input. For that you need:

sed -n "s/.*'\([^']\+\)'.*/\1/p"

jtbandes

Posted 2009-07-22T23:26:04.717

Reputation: 8 350

1@jtbandes: You don't need the extended features for this expression.. I just requires 3 escape characters for ( ) + use \( \) \+: This is effectively the same: sed "s/.*'\([^']\+\)'.*/\1/" – Peter.O – 2012-01-11T01:38:38.717

3This doesn't work for multiline input. For that you need:

sed -n "s/.*'\([^']\+\)'.*/\1/p" – phreakhead – 2012-10-10T18:15:51.513

Thanks, had forgotten about sed. But to clarify, sed doesn't take the argument -E.. – Torandi – 2009-07-22T23:36:22.197

1Hm, it does on my machine (Mac OS X). Upon further examination, in the man page: "The -E, -a and -i options are non-standard FreeBSD extensions and may not be available on other operating systems." – jtbandes – 2009-07-22T23:40:06.057

Okay, it doesn't on mine (debian), what is -E supposed to do? – Torandi – 2009-07-22T23:42:50.280

1It's similar to grep's -E: "Interpret regular expressions as extended (modern) regular expressions rather than basic regular expressions (BRE's). The re_format(7) manual page fully describes both formats." – jtbandes – 2009-07-22T23:44:06.203

1-r seems to to that for me. – Torandi – 2009-07-22T23:46:16.650

And I don't have -r. Oh well! – jtbandes – 2009-07-22T23:49:53.430

28

While grep can't output a specific group, you can use lookahead and behind assertions to achieve what your after:

echo "foo 'bar'" | grep -Po "(?<=')[^']+(?=')"

Aldrik

Posted 2009-07-22T23:26:04.717

Reputation: 706

8grep -P is not available on all platforms. But if it is, using lookahead/behind is a very nice way of solving the problem. – Sébastien – 2012-06-13T13:16:15.097

1

Is grep intelligent with the look-behind assertions? How does it perform with long look-behinds? Is it integrating the look-behinds into some sort of "suffix tree" with the rest of the regex?

– Ross Rogers – 2012-10-01T18:33:13.747

4

You can use \K to reset and discard the left hand match text along with a lookahead which is not added to the match text:

$ echo "foo 'bar'" | grep -oP "'\K[^']+(?=')"
bar

GNU grep only.

drewk

Posted 2009-07-22T23:26:04.717

Reputation: 984