Pipe encontrar en grep -v

18

Estoy tratando de encontrar todos los archivos que son de cierto tipo y no contienen una determinada cadena. Estoy tratando de hacerlo canalizando find a grep -v

ejemplo:

find -type f -name '*.java' | xargs grep -v "something something"

Parece que esto no funciona. Parece que solo está devolviendo todos los archivos que encontró el comando find. Lo que estoy tratando de hacer es básicamente encontrar todos los archivos .java que coincidan con un nombre de archivo determinado (por ejemplo, termina con 'Pb' como en SessionPb.java) y que no tienen un 'extiende algo' dentro de él.

Mi sospecha es que lo estoy haciendo mal. Entonces, ¿cómo debería ser el comando en su lugar?

Hyangelo
fuente
puedes agregar lo que te hace pensar que no funcionó. ¿Quizás tu expresión grep es demasiado explícita? necesita un '-i' para la insensibilidad a mayúsculas y minúsculas? Vea mi respuesta a continuación también ...
lornix

Respuestas:

21

No hay necesidad xargsaquí. También debe usar grepcon la -Lopción (archivos sin coincidencia), porque de lo contrario generará el contenido del archivo en lugar de su nombre, como en su ejemplo.

find . -type f -iname "*.java" -exec grep -L "something somethin" {} \+
prisa
fuente
1
-LYa tiene negociación, porque significa files _without_ match. Por lo tanto, no necesita la -vopción aquí.
prisa el
3
no con el extra + al final.
lynxlynxlynx
2
@ user946850 cada vez que escribo, find -exec \+alguien me escribe que es mucho mejor usar xargs. ¿Por qué nadie se ve hombre antes de escribir un comentario? (:
rush
55
@ user946850 -exec ... {} \+no es equivalente a xargs. ¡Lea la documentación de findutils! (¡Trabajé bastante duro en ello!)
James Youngman el
2
@ user946850 sí. Una de las diferencias es que (por defecto) xargsprocesa su entrada y separa los argumentos en el espacio en blanco. Las cotizaciones también son especiales (por defecto) para xargs. Ninguna de estas cosas es cierta -exec ... {} +. Las versiones anteriores de xargssolían considerar el guión bajo como un indicador EOF, pero este ya no es el caso.
James Youngman
7

Casi lo tienes realmente ...

find . -type f -iname "*.java" -print0 | xargs -0 grep -v "something something"

El punto '.' dice que comience desde aquí. (el tuyo lo implica ... pero nunca asumas).

-iname utiliza la búsqueda que no distingue entre mayúsculas y minúsculas, por si acaso (o solo en no caso).
-print0 envía nombres de archivo a xargs con un carácter \ x00 final, lo que evita problemas con nombres de archivos que tienen espacios en ellos.

el '-0' en xargs dice esperar nombres de archivo que terminan con \ x00 en lugar de retornos.

y tu comando grep ...

Más o menos lo tengo.


EDITAR::

De su actualización:

find . -type f -iname "*pb.java" -print0 | xargs -0 grep -iL "something"

debería ayudar. (Se agregó -L de la respuesta de @ rush, buen trabajo)

Tengo la idea de que tu grep necesita la opción '-i' o ser menos explícito.

Pruebe el comando en partes ... ¿ESTO genera nombres de archivo que parecen correctos?

find . -type f -iname "*pb.java"

Si es así, es probable que su problema sea que su patrón de búsqueda grep no coincida (¿error de ortografía? ¡Sucede!), O simplemente no hay coincidencias.

Absolutamente peor de los casos:

grep -riL "something" *

hará MUCHO más trabajo buscando todo, pero debería darle algo de salida.

lornix
fuente
Intenté sus modificaciones y todavía no obtengo el resultado que esperaba. Intentaré actualizar la pregunta para que quede más clara.
Hyangelo
Si el autor de la pregunta solo quiere encontrar nombres de archivo, ¿no debería ser grep 'grep -l -v'?
Bruce Ediger
está buscando contenidos específicos en los archivos * .java
lornix
xargs -0 grep -v "something something"De lo xargs -0 grep -v "something something" /dev/nullcontrario, obtendrá resultados extraños cuando find no produce archivos coincidentes.
James Youngman
{Sonríe} sí, en algún lugar allí la lógica se puso complicada. Nada como una prueba múltiple de lógica falsa inversa para que te duela la cabeza.
lornix
4

La computadora está siendo una computadora: está haciendo lo que le dijiste que hiciera en lugar de lo que querías que hiciera.

grep -v "something something"imprime todas las líneas que no contienen something something. Por ejemplo, imprime dos líneas entre las tres siguientes:

hello world
this is something something
something else

Para imprimir archivos que no contienen en extends SomethingSomethingninguna parte, use la -Lopción:

grep -L -E 'extends[[:space:]]+SomethingSomething' FILENAME…

Algunas versiones de grep no tienen la -Lopción ( POSIX no lo especifica ). Si el tuyo no lo hace, haz que no imprima nada y usa el código de retorno para que el shell de llamada haga lo que sea que deba hacer.

grep -q -E 'extends[[:space:]]+SomethingSomething' FILENAME ||
echo "$FILENAME"

Alternativamente, use awk.

awk '
    FNR == 1 && NR != 1 && !found { print fn }
    FNR == 1 { fn = FILENAME; found = 0; }
    /extends[[:space:]]+SomethingSomething/ { found = 1 }
    END { if (fn != "" && !found) print fn }
'

En Linux o Cygwin (u otro sistema con GNU grep), no necesita usar find, ya que grepes capaz de recurrir.

grep -R --include='*.java' -L -E 'extends[[:space:]]+SomethingSomething'

Si su shell es ksh o bash o zsh, puede hacer que el shell coincida con el nombre del archivo. En bash, corre set -o globstarprimero (puedes poner esto en tu ~/.bashrc).

grep -L -E 'extends[[:space:]]+SomethingSomething' **/*.java
Gilles 'SO- deja de ser malvado'
fuente
Wow, esto es aún mejor. Estaba usando 'extend (/ s) + SomethingSomething' que parecía funcionar hasta donde podía ver. ¿Hay alguna diferencia con esta sintaxis con la especificada en la versión Extended RegEx?
Hyangelo
@Hyangelo \ses una extensión grep de GNU, que creo que es sinónimo de [[:space:]].
Gilles 'SO- deja de ser malvado'