¿Cómo usar grep para buscar una línea con una de dos palabras pero no ambas?
11
Quiero buscar líneas con 'word1' XOR 'word2' en un archivo de texto. Por lo tanto, debería generar líneas con word1, word2 pero no las líneas con ambas palabras. Quería usar el XOR pero no sé cómo escribir eso en la línea de comando de Linux.
grep 'word1\|word2' text.txtbusca líneas que contengan word1o word2. Esto incluye líneas que contienen ambos.
grep word1 text.txt | grep word2busca líneas que contengan word1y word2. Las dos palabras pueden superponerse (por ejemplo, foobarcontiene fooy ob). Otra forma de buscar líneas que contengan ambas palabras, pero solo de forma no superpuesta, es buscarlas en cualquier orden:grep 'word1.*word2\|word2.*word1' text.txt
grep word1 text.txt | grep -v word2busca líneas que contienen word1pero no word2. La -vopción le dice a grep que mantenga líneas no coincidentes y que elimine las líneas coincidentes, en lugar de lo contrario. Esto le da la mitad de los resultados que deseaba. Al agregar la búsqueda simétrica, obtienes todas las líneas que contienen exactamente una de las palabras.
Alternativamente, puede comenzar desde las líneas que contienen cualquiera de las palabras y eliminar las líneas que contienen ambas palabras. Dados los bloques de construcción anteriores, esto es fácil si las palabras no se superponen.
Gracias, esto es exactamente lo que estaba buscando. Las otras respuestas también son muy interesantes, así que las miraré. Gracias a todos por contribuir.
Si desea considerar solo palabras completas (que no hay fooni baren foobarni barbarpor ejemplo), deberá decidir cómo se delimitan esas palabras. Si es por cualquier carácter que no sean letras, dígitos y guiones bajos, como lo hace la -wopción de muchas grepimplementaciones, entonces los cambiaría a:
Para sedeso se vuelve un poco complicado a menos que tenga una sedimplementación como GNU sed que admita \</ \>como límites de palabras como lo awkhace GNU .
Stephane, ¡por favor escribe un libro sobre scripting de shell!
pfnuesel
Lo siento, solo comencé la línea de comandos hace unas semanas. ¿Cómo lo forzaría a buscar solo palabras? Intenté -Pw y -wP pero esto me dio un resultado incorrecto. También intenté usar '' entre * word1 / * word2 y alrededor de word1 / word2.
Lukali
@Lukali, ver edición.
Stéphane Chazelas
2
Una solución bash:
#!/bin/bash
while (( $# )); do
a=0 ; [[ $1 =~ foo ]] && a=1
b=0 ; [[ $1 =~ bar ]] && b=1
(( a ^ b )) && echo "$1"
shift
done
Para probarlo:
$ ./script {foo,bar}\ {foo,bar} neither
foo foo
bar bar
Con GNU
awk
:O portablemente:
Con un
grep
soporte para-P
(PCRE):Con
sed
:Si desea considerar solo palabras completas (que no hay
foo
nibar
enfoobar
nibarbar
por ejemplo), deberá decidir cómo se delimitan esas palabras. Si es por cualquier carácter que no sean letras, dígitos y guiones bajos, como lo hace la-w
opción de muchasgrep
implementaciones, entonces los cambiaría a:Para
sed
eso se vuelve un poco complicado a menos que tenga unased
implementación como GNUsed
que admita\<
/\>
como límites de palabras como loawk
hace GNU .fuente
Una solución bash:
Para probarlo:
fuente