Com sintaxe grep padrão e BRE:
$ grep -x '\(.*[^r]\)\{0,1\}rr\([^r].*\)\{0,1\}' < file
rr
abcrr d
rarrrrrr aaa rrqq
kdhdrraa rrzaza
(substitua rr por r\{42\} por 42 r s)
Corresponde e x efetivamente (é a linha inteira) em rr opcionalmente ( \{0,1\} sendo 0 ou 1, equivalente a ERE ? ) precedido por uma sequência de caracteres que termina em um caractere diferente de r ( [^r] ) e, opcionalmente, seguido por uma sequência de caracteres começando com um caractere diferente de r .
Com ERE:
$ grep -E '(^|[^r])rr([^r]|$)' < file rr abcrr d rarrrrrr aaa rrqq kdhdrraa rrzaza
(substitua rr por r{42} por 42 r s)
Isso é rr precedido pelo início da linha ou por um caractere diferente de r e seguido pelo final da linha ou por um caractere diferente de r .
Com PCRE (não padrão):
$ grep -P '(?<!r)rr(?!r)' < file rr abcrr d rarrrrrr aaa rrqq kdhdrraa rrzaza
(substitua rr por r{42} por 42 r s)
Ou seja, rr não foi precedido nem seguido por r .
Com Aumentado RE (ast-aberto grep ):
$ grep -xX '(.*r)!rr(r.*)!' < file rr abcrr d rarrrrrr aaa rrqq kdhdrraa rrzaza
(substitua rr por r{42} por 42 r s)