Con grepimplementaciones que admiten expresiones regulares tipo perl (like pcregrepo GNU o ast-open grep -P), puede hacerlo en una grepinvocación con:
grep -P '^(?=.*pat1)(?!.*pat2)|^(?=.*pat2)(?!.*pat1)'
Es decir, encontrar las líneas que coinciden pat1pero no pat2, o pat2no pat1.
(?=...)y (?!...)son respectivamente operadores de anticipación y de anticipación negativos. Entonces, técnicamente, lo anterior busca el comienzo del sujeto ( ^) siempre que sea seguido .*pat1y no seguido .*pat2, o lo mismo con pat1e pat2invertido.
Eso es subóptimo para las líneas que contienen ambos patrones, ya que luego se buscarían dos veces. En su lugar, podría usar operadores perl más avanzados como:
grep -P '^(?=.*pat1|())(?(1)(?=.*pat2)|(?!.*pat2))'
(?(1)yespattern|nopattern)coincide con yespatternsi el grupo de captura 1st (vacío ()arriba) coincide, y de lo nopatterncontrario. Si esa ()partidos, eso significa que pat1no coinciden, por lo que buscamos pat2(aspecto positivo por delante), y buscamos no pat2 de otro modo (por delante aspecto negativo).
Con sed, podrías escribirlo:
sed -ne '/pat1/{/pat2/!p;d;}' -e '/pat2/p'
[a-z][a-z0-9]\(,7\}\(\.[a-z0-9]\{,3\}\)+? (2) ¿Qué sucede si una de las palabras / patrones aparece más de una vez en una línea (y la otra no aparece)? ¿Es eso equivalente a la palabra que aparece una vez, o cuenta como ocurrencias múltiples?