Cómo buscar aparición de una palabra y ausencia de otra usando grep

Cómo buscar aparición de una palabra y ausencia de otra usando grep

Tengo un archivo con contenido similar a:

google.com,9,AB+CD,nonAB+nonCD
youtube.com,9,AB+CD,AB+CD
facebook.com,20,AB+CD,nonCD

El número de columnas no es fijo. Pero la primera columna es una URL, la segunda es un número, comenzando desde la tercera son palabras clave separadas por comas, pero varían de un sitio a otro.

Quiero contar la cantidad de URL (líneas) donde puedo controlar qué palabras clave hay en la línea. Por ejemplo,
1) AB+CDsin nonABy nonCD. Nota: la palabra AB+CD puede aparecer muchas veces. 2) AB+CD sin que aparezca nonCD(pero está bien si hay algo más)

Cómo buscar una cadena en una línea Y asegurar la ausencia de otra cadena. Cuando uso:

grep 'AB+CD' test.txt > result.txt

Imprime cada línea donde se encuentra 'AB+CD'.

¿Qué pasa si quiero imprimir la línea donde solo hay 'AB+CD' para obtener:

youtube.com,9,AB+CD,AB+CD

O hay 'AB+CD' con cualquier otra cosa excepto 'nonAB' para obtener:

youtube.com,9,AB+CD,AB+CD
facebook.com,20,AB+CD,nonCD

Respuesta1

Si solo deseas una búsqueda de texto sin formato sin preocuparte por las columnas, puedes encadenar la coincidencia invertida grep -vde esta manera:

cat input.txt | grep 'IncludedText' | grep -v 'ExcludedText'

Si desea realizar un filtrado adecuado por columna, querrá utilizar algo como awk.

Respuesta2

Trucos generales:

  1. Líneas que contienen foomás líneas que contienen bar( foo OR bar):

    grep -e foo -e bar
    
  2. Líneas que contienen fooy baren la misma línea ( foo AND bar):

    grep foo | grep bar
    
  3. Líneas que no contienen baz( NOT baz):

    grep -v baz
    

Con estos ladrillos puedes construir tu lógica. El problema -vno se limita a un solo patrón, sino que es global grep(al menos en mi Debian). Esto hace NOT (foo OR bar)posible:

grep -v -e foo -e bar

que equivale a (NOT foo) AND (NOT bar):

grep -v foo | grep -v bar

Sin embargo NOT (foo AND bar)(lógicamente equivalente a (NOT foo) OR (NOT bar)) no es tan fácil. Podemos intentar obtener foo AND barcon unsoltero(extendido) grep:

  1. Nuevamente líneas que contienen fooy baren la misma línea ( foo AND bar):

    grep -E 'foo.*bar|bar.*foo'
    

Ahora para conseguir NOT (foo AND bar):

grep -v -E 'foo.*bar|bar.*foo'

No estoy seguro de si lo anterior es un sistema completo cuando se trata de más de dos patrones. Todavía algunos de sus problemas se pueden resolver con él. Ejemplo:

AB+CDsin nonABynonCD

Si te entiendo bien esAB+CD AND NOT (nonAB OR nonCD)

grep AB+CD | grep -v -e nonAB -e nonCD

Observe que esta solicitud complica las cosas:

Quiero imprimir la línea donde solo hay 'AB+CD'

Se puede decir grep ,AB+CD,AB+CDque servirá, pero dado que "el número de columnas no es fijo", supongo que le gustaría diferenciar estas dos líneas:

youtube.com,9,AB+CD,AB+CD,AB+CD
youtube.com,9,AB+CD,AB+CD,banana

En tales casos, necesita expresiones regulares más complicadas u otras herramientas (como awk).

Respuesta3

Si bien obtendrás una respuesta aquí, deberías echar un vistazo ahombre grep(puede ser abrumador) yalgunos ejemplos. Por el momento aquí va la respuesta:

Usandogrep

grep "foobar" test.txt

buscará líneas que tengan una palabra foobaren el archivo test.txty mostrará todas las apariciones, mientras que,

grep "foo" -v "bar" test.txt

Buscará líneas que tengan palabra foopero no bar. Obtenemos esto debido a-vinterruptor para el cual la página de manual explica:

-v, --invert-match
    Invert the sense of matching, to select non-matching lines.
    (-v is specified by POSIX .)

Simplemente significa que buscará líneas que tengan esas palabras ( aquí bar), pero las excluirá en la visualización final. De este modoinvirtiendo la búsqueda.

Además, para contar el número de líneas que coinciden con la búsqueda, utilice-ccambiar :

-c, --count
    Suppress normal output; instead print a count of matching lines
    for each input file. With the -v, --invert-match option (see below),
    count non-matching lines. (-c is specified by POSIX .)

Como ejercicio personal, pruebe la búsqueda grep en el archivoFoobar.

La respuesta

Busque AB+CDignorar nonABy nonCDcontar URL:

grep "AB+CD" test | grep -cve "non"

donde -v "non"simplemente ignorará a ambos nonABy nonCDcomo ambos tienen nonen ellos. Y -cdará el recuento total de los partidos en lugar de imprimirlos. Para imprimir líneas coincidentes, simplemente ignore -c.

Puedes usarlo para invertidos separados:

grep "AB+CD" test | grep -cve "nonAB\|nonCD"

donde \|representa ORy significa cualquiera de nonABononCD exactopalabra especificada por-ecambiar.


Te aconsejaría quever la respuesta de Kamil, lea las páginas de manual (ya conoce el comando) tanto como pueda, esfuércese mientras busca cosas en línea y sirva a la comunidad. No dude en agregar más detalles para responder.

información relacionada