¿Cómo grep, excluyendo algunos patrones?

84

Me gustaría encontrar líneas en archivos con la aparición de algún patrón y la ausencia de algún otro patrón. Por ejemplo, necesito encontrar todos los archivos / líneas, loomexcepto los que tienen gloom. Entonces, puedo encontrar loomcon el comando:

grep -n 'loom' ~/projects/**/trunk/src/**/*.@(h|cpp)

Ahora, quiero buscar loomexcluyendo gloom. Sin embargo, los dos comandos siguientes fallaron:

grep -v 'gloom' -n 'loom' ~/projects/**/trunk/src/**/*.@(h|cpp)
grep -n 'loom' -v 'gloom' ~/projects/**/trunk/src/**/*.@(h|cpp)

¿Qué debo hacer para lograr mi objetivo?

EDITAR 1: Me refiero a esoloomygloomson las secuencias de caracteres (no necesariamente las palabras). Entonces, necesito, por ejemplo,bloombergen la salida del comando y no lo necesitoungloomy.

EDICIÓN 2: Hay una muestra de mis expectativas. Las dos líneas siguientes están en la salida del comando:

Me enfrenté a los iconos que asomaban a través del velo de incienso.

Arty está llorando en un día sombrío .

Las dos líneas siguientes no están en la salida del comando:

Es lúgubre o terrible, grandes muckle doolders o 'cloods.

En la ronda suroeste de la sala heigh pyntit

Telar
fuente
¿Está buscando archivos que coincidan con sus criterios de líneas que coincidan con sus criterios?
Juto
Estoy buscando archivos con líneas que coincidan con mis criterios. Y quiero ver la lista de todos los conjuntos de nombre de archivo + número de línea coincidente + línea coincidente en sí.
Telar
Si la línea fuera there is a loom in the gloom, ¿le gustaría que se imprimiera? Solo trato de entender si solo está buscando líneas donde se produce el telar de manera que no sea como parte de la penumbra o si realmente desea excluir las líneas que contienen la penumbra incluso cuando el telar aparece solo en otra parte de la línea. Publicar alguna entrada de muestra y salida esperada ayudaría.
Ed Morton
¿Entonces tu pregunta es realmente How do I find lines containing the string "loom" where "loom" is not preceded by the letter "g"? Si hubiera publicado alguna entrada de muestra y la salida deseada, habría ayudado mucho. La respuesta a esa pregunta se incluye en las respuestas a continuación.
Ed Morton
1
@EdMorton - Sí, tienes razón - Necesito todas las líneas, donde ocurre loomsin precedido g. (Lo siento. Comencé a comentar ayer, pero nunca terminé. Este comentario fue enviado accidentalmente.)
Loom

Respuestas:

102

¿Qué tal simplemente encadenar a los greps?

grep -n 'loom' ~/projects/**/trunk/src/**/*.@(h|cpp) | grep -v 'gloom'
houbysoft
fuente
13
Justo a tiempo. Funciona perfectamente. -v es la opción para excluir. Gracias
Ravi Krishna P
2
De la pregunta: Entonces, necesito, por ejemplo, bloombergen la salida del comando y no lo necesito ungloomy. Si una sola línea contuviera '... y Bloomberg no es sombrío sobre las perspectivas ...', eliminaría esa línea, pero es deseada (porque si contiene bloomberg).
Jonathan Leffler
23

Otra solución sin encadenamiento grep:

egrep '(^|[^g])loom' ~/projects/**/trunk/src/**/*.@(h|cpp)

Entre paréntesis, excluye el carácter gantes de cualquier aparición de loom, a menos que loomsean los primeros caracteres de la línea.

Bentoy13
fuente
9

Un poco viejo, pero bueno ...

La solución más votada de @houbysoft no funcionará ya que excluirá cualquier línea con "penumbra" en ella, incluso si tiene "loom". De acuerdo con las expectativas de OP, necesitamos incluir líneas con "telar", incluso si también tienen "penumbra" en ellas. Esta línea debe estar en la salida "Arty está haciendo un slooming en un día sombrío", pero esto será excluido por un grep encadenado como

grep -n 'loom' ~/projects/**/trunk/src/**/*.@(h|cpp) | grep -v 'gloom'

En cambio, el ejemplo de expresión regular egrep de Bentoy13 funciona mejor

egrep '(^|[^g])loom' ~/projects/**/trunk/src/**/*.@(h|cpp)

ya que incluirá cualquier línea con "telar" en ella, independientemente de si tiene o no "penumbra". Por otro lado, si solo tiene pesimismo, no lo incluirá, que es precisamente el comportamiento que OP quiere.

Sam
fuente
8

Simplemente use awk, es mucho más simple que grep ya que le permite expresar claramente las condiciones compuestas.

Si desea omitir líneas que contienen ambos loomy gloom:

awk '/loom/ && !/gloom/{ print FILENAME, FNR, $0 }' ~/projects/**/trunk/src/**/*.@(h|cpp)

o si quieres imprimirlos:

awk '/(^|[^g])loom/{ print FILENAME, FNR, $0 }' ~/projects/**/trunk/src/**/*.@(h|cpp)

y si la realidad es que solo quieres líneas donde loomaparezca como una palabra por sí misma:

awk '/\<loom\>/{ print FILENAME, FNR, $0 }' ~/projects/**/trunk/src/**/*.@(h|cpp)
Ed Morton
fuente
3
Piense en cómo se iba a escribir un comando grep para obtener líneas que contienen abcy defy ghien cualquier orden. Ahora compare eso con awk '/abc/ && /def/ && /ghi/'. Ahora piense en cómo awk '/loom/ && !/gloom/'se escribe el equivalente grep de en las respuestas de esta página.
Ed Morton
No estoy muy familiarizado con awk, aparentemente hay libros sobre este comando por sí solo. Por ahora estoy bien con grep, tal vez algún día diga lo mismo que tú. :)
Juto
2
awk es LA herramienta estándar de UNX (es decir, disponible en TODAS las instalaciones de UNIX) para procesar archivos de texto. Para eso se inventó y es muy bueno en eso. Si está en UNIX y analiza archivos de texto, aprenda awk del libro Programación eficaz de Awk, tercera edición de Arnold Robins. Hay un pequeño cambio de paradigma que hay que superar en relación con la condition { action }sintaxis de awks, pero luego es muy sencillo para cualquiera con cualquier experiencia en lenguaje C u otro lenguaje basado en Algol.
Ed Morton
Bono: salida como grep -Hn --color:awk '/loom/ && !/gloom/ { gsub(/loom/, color("1;31") "&" color(0)); print color(35) FILENAME color(36) ":" color(32) FNR color(36) ":" color(0) $0; }; function color(c) { return "\033[" c "m"; }'
enredo
6

-v es la bandera de "coincidencia invertida", por lo que la canalización es una muy buena forma:

grep "loom" ~/projects/**/trunk/src/**/*.@(h|cpp)| grep -v "gloom"

Oleg Kokorin
fuente
5

/ * ¿Podrías verte algo así?

grep -vn "gloom" `grep -l "loom" ~/projects/**/trunk/src/**/*.@(h|cpp)`

Los BACKQUOTES se utilizan como corchetes para los comandos, por lo que en este caso con -l habilitado, el código en BACKQUOTES le devolverá los nombres de los archivos, luego con -vn para hacer lo que quería: tener nombres de archivo, números de línea y también las líneas reales.

ACTUALIZAR O con xargs

grep -l "loom" ~/projects/**/trunk/src/**/*.@(h|cpp) | xargs grep -vn "gloom"

Espero que ayude.*/

Por favor ignore lo que he escrito arriba, es una tontería.

grep -n "loom" `grep -l "loom" tt4.txt` | grep -v "gloom"

               #this part gets the filenames with "loom"
#this part gets the lines with "loom"
                                          #this part gets the linenumber,
                                          #filename and actual line
Juto
fuente
4

Puede utilizar grep -P(perl regex) compatible negative lookbehind:

grep -P '(?<!g)loom\b' ~/projects/**/trunk/src/**/*.@(h|cpp)

Agregué \bpara límites de palabras.

anubhava
fuente
2
No necesitas mirar atrás, \([^g]\|^\)funciona. Y esto no excluye las líneas con loomy gloom.
Kevin
@Kevin: OP quiere encontrar líneas con telar pero not gloom.
anubhava
Exactamente. Si una línea tiene ambos, no la quiere, pero de todas formas coincidirá.
Kevin
@Kevin: Esto NO coincidirá con la penumbra, sino con el telar (como OP quiere).
Anubhava
De la pregunta: Entonces, necesito, por ejemplo, bloombergen la salida del comando y no lo necesito ungloomy. Por tanto, los límites de las palabras son contraproducentes.
Jonathan Leffler
3
grep -n 'loom' ~/projects/**/trunk/src/**/*.@(h|cpp) | grep -v 'gloom'
Jiminion
fuente
De la pregunta: Entonces, necesito, por ejemplo, bloombergen la salida del comando y no lo necesito ungloomy. Si una sola línea contuviera '... y Bloomberg no es sombrío sobre las perspectivas ...', eliminaría esa línea, pero es deseada (porque si contiene bloomberg).
Jonathan Leffler
@JonathanLeffler "Necesito encontrar todos los archivos / líneas, incluido el telar, excepto los que tienen pesimismo".
Jiminion
3

¡Simplemente utilícelo! grep -vvarias veces.

Contenido del archivo

[root@server]# cat file
1
2
3
4
5

Excluir la línea o hacer coincidir

[root@server]# cat file |grep -v 3
1
2
4
5

Excluir la línea o hacer coincidir varios

[root@server]# cat file |grep -v 3 |grep -v 5
1
2
4
Tiborcz beso
fuente
0

Pregunta: busque 'loom' excluyendo 'penumbra'.
Responder:

grep -w 'loom' ~/projects/**/trunk/src/**/*.@(h|cpp)
Abhinandan
fuente
1
De la pregunta: Entonces, necesito, por ejemplo, bloombergen la salida del comando y no lo necesito ungloomy. No creo que esa -wsea ​​la solución a ese enigma.
Jonathan Leffler