Estoy tratando de usar grep
para mostrar solo las líneas que contienen cualquiera de las dos palabras, si solo una de ellas aparece en la línea, pero no si están en la misma línea.
Hasta ahora lo he intentado grep pattern1 | grep pattern2 | ...
pero no obtuve el resultado que esperaba.
[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?Respuestas:
Una herramienta que no
grep
sea el camino a seguir.Usando perl, por ejemplo, el comando sería:
perl -ne
ejecuta el comando dado sobre cada línea de stdin, que en este caso imprime la línea si coincide/pattern1/ xor /pattern2/
o, en otras palabras, coincide con un patrón pero no con el otro (exclusivo o).Esto funciona para el patrón en cualquier orden, y debería tener un mejor rendimiento que las invocaciones múltiples de
grep
, y también es menos tipeado.O, incluso más corto, con awk:
o para versiones de awk que no tienen
xor
:fuente
xor
disponible solo en GNU Awk?/pattern1/+/pattern2/==1
irxor
falta.\b
) en los patrones mismos, es decir\bword\b
.Con GNU
grep
, puede pasar ambas palabrasgrep
y luego eliminar las líneas que contienen ambos patrones.fuente
Probar con
egrep
fuente
grep -e foo -e bar | grep -v -e 'foo.*bar' -e 'bar.*foo'
Direct invocation as either egrep or fgrep is deprecated
- prefierogrep -E
-f
y-e
opciones, aunque las más antiguasegrep
yfgrep
continuarán siendo compatibles durante un tiempo.grep
(que soporta-F
,-E
,-e
,-f
como requiere POSIX) está en/usr/xpg4/bin
. Las utilidades en/bin
son anticuadas.Con
grep
implementaciones que admiten expresiones regulares tipo perl (likepcregrep
o GNU o ast-opengrep -P
), puede hacerlo en unagrep
invocación con:Es decir, encontrar las líneas que coinciden
pat1
pero nopat2
, opat2
nopat1
.(?=...)
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.*pat1
y no seguido.*pat2
, o lo mismo conpat1
epat2
invertido.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:
(?(1)yespattern|nopattern)
coincide conyespattern
si el grupo de captura1
st (vacío()
arriba) coincide, y de lonopattern
contrario. Si esa()
partidos, eso significa quepat1
no coinciden, por lo que buscamospat2
(aspecto positivo por delante), y buscamos nopat2
de otro modo (por delante aspecto negativo).Con
sed
, podrías escribirlo:fuente
grep: the -P option only supports a single pattern
, al menos en todos los sistemas a los que tengo acceso. Sin embargo, +1 para tu segunda solución.grep
.pcregrep
y grep ast-open no tienen ese problema. He reemplazado el múltiplo-e
con el operador de alternancia RE, por lo que ahora debería funcionar con GNUgrep
también.En términos booleanos, está buscando A xor B, que se puede escribir como
(A y no B)
o
(B y no A)
Dado que su pregunta no menciona que le preocupa el orden de la salida siempre que se muestren las líneas coincidentes, la expansión booleana de A xor B es bastante simple en grep:
fuente
sort | uniq
.Para el siguiente ejemplo:
Esto se puede hacer simplemente con
grep -E
,uniq
ywc
.Si
grep
se compila con expresiones regulares de Perl, puede coincidir en la última aparición en lugar de necesitar canalizar auniq
:Salida del resultado:
Una frase:
Si no desea codificar el patrón, ensamblarlo con un conjunto variable de elementos puede automatizarse con una función.
Esto también se puede hacer de forma nativa en Bash como una función sin canalizaciones o procesos adicionales, pero sería más complicado y probablemente esté fuera del alcance de su pregunta.
fuente
Big apple\n
ypear-shaped\n
, entonces la salida debe contener ambas líneas. Su solución obtendría una cuenta de 2; la versión larga informaría "Ambas palabras coinciden" (que es una respuesta a la pregunta incorrecta) y la versión corta no diría nada en absoluto. (3) Una sugerencia: usar-o
aquí es una muy mala idea, ya que oculta las líneas que contienen las coincidencias, por lo que no puede ver cuándo ambas palabras aparecen en la misma línea. ... (Continúa)uniq
/sort -u
y la elegante expresión regular de Perl para que coincida solo con la última aparición en cada línea realmente no se suman a una respuesta útil a esta pregunta. Pero, incluso si lo hicieran, sería una mala respuesta porque no explicas cómo contribuyen a responder la pregunta. (Ver la respuesta de Stéphane Chazelas para un ejemplo de una buena explicación.)