11

On the perlre's extended patterns page we can read about \K:

Keep the stuff left of the \K, don't include it in $&

Here is the practical example using GNU grep (which actually keeps stuff right of the \K):

$ echo "foo bar buzz" | grep -Po "foo \Kbar buzz"
bar buzz

Is there any opposite sequence of \K?

For example to print just bar, like:

$ echo "foo bar buzz" | grep -Po "foo \Kbar\X buzz"
bar
kenorb
  • 20,250
  • 14
  • 140
  • 164
  • Is sed also valid? `echo "foo bar buzz" | sed -E '/foo (bar) buzz/s//\1/'` –  Apr 13 '18 at 03:25
  • @isaac I don't see anything in that duplicate that answers the question here. – roaima Apr 13 '18 at 11:26
  • @roaima The [first answer in there](https://unix.stackexchange.com/a/13472/265604) presents the same zero-width lookahead (?=...) `grep -oP 'foo \K\w+(?= bar)' test.txt` that the **accepted** answer use here. It seems to me that the answer there also solve the issue here. –  Apr 13 '18 at 11:45

1 Answers1

18

In this case, zero-width lookahead (?=...) does what you want:

$ echo foo bar buzz | grep -Po "foo \Kbar(?= buzz)"
bar

It does require some extra parentheses. There is no single-character escape for lookahead the way there is for \K.

\K is really just a zero-width lookbehind for everything so far, so this is also equivalent to

echo foo bar buzz | grep -Po "(?<=foo )bar(?= buzz)"

which I find easier to follow personally.

Michael Homer
  • 74,824
  • 17
  • 212
  • 233
  • 5
    IIRC the difference between `pat\K` and `(?<=pat)` is that `\K` permits variable-length lookbehind - AFAIK there's no such restriction for the lookahead version (which is perhaps why there's no lookahead equivalent of `\K`) – steeldriver Apr 12 '18 at 23:40
  • That's my understanding as well, and that it can be more efficient than regular lookbehind (because there's no extra backtracking?), so it can be preferable sometimes. – Michael Homer Apr 12 '18 at 23:43
  • To demonstrate the difference, `echo foooooo bar | grep -oP "(?<=foo+) \Kbar"` will fail, while `$ echo foooooo bar | grep -oP "foo+ \Kbar" bar` will yield `bar`. – Maroun Jul 21 '22 at 06:38