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+CD
sin nonAB
y 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 -v
de 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:
Líneas que contienen
foo
más líneas que contienenbar
(foo OR bar
):grep -e foo -e bar
Líneas que contienen
foo
ybar
en la misma línea (foo AND bar
):grep foo | grep bar
Líneas que no contienen
baz
(NOT baz
):grep -v baz
Con estos ladrillos puedes construir tu lógica. El problema -v
no 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 bar
con unsoltero(extendido) grep
:
Nuevamente líneas que contienen
foo
ybar
en 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+CD
sinnonAB
ynonCD
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+CD
que 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 foobar
en el archivo test.txt
y mostrará todas las apariciones, mientras que,
grep "foo" -v "bar" test.txt
Buscará líneas que tengan palabra foo
pero no bar
. Obtenemos esto debido a-v
interruptor 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-c
cambiar :
-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+CD
ignorar nonAB
y nonCD
contar URL:
grep "AB+CD" test | grep -cve "non"
donde -v "non"
simplemente ignorará a ambos nonAB
y nonCD
como ambos tienen non
en ellos. Y -c
dará 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 OR
y significa cualquiera de nonAB
ononCD
exactopalabra especificada por-e
cambiar.
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.