Well, that's a tricky one. Here's an imperfect solution:
grep . -Prle '(?s)(?<ref>foo\d+)\b(?! bar).*\k<ref>(*SKIP)(*FAIL)|foo\d+ bar'
Why is it imperfect? Because if you have a file containing foo123 foo456 bar foo123 bar
, it won't detect the foo456 bar
part. If this situation cannot happen in your set of files, then I suppose you're fine.
This makes use of the (*SKIP)(*FAIL)
trick, once you learn that the rest of the pattern should be pretty clear.
So maybe plain regex isn't the best solution here, let's just write a one-liner script instead:
find . -type f -execdir perl -e 'while(<>) { while(/foo(\d+)( bar)?/g) { if ($2) { exit 0 if !$n{$1} } else { $n{$1} = 1 } } } exit 1;' {} \; -print
That one does the job and is hopefully more understandable :)