En Linux, ¿cómo puedo encontrar todos los archivos que contienen una cadena y eliminarlos?

17

Quiero eliminar todos los archivos que contienen la cadena foo. ¿Cómo puedo hacer esto usando bash en Linux?

Kitsos
fuente
esa cadena es su nombre de archivo?
rɑːdʒɑ
3
Por favor aclare: ¿desea eliminar archivos cuyo nombre contiene foo(p myfoo.jpg. Ej. ) O archivos que contienen la secuencia de bytes foo(que pueden incluir archivos binarios que contienen esa secuencia de bytes)?
hammar

Respuestas:

33

Aquí hay una manera segura:

grep -lrIZ foo . | xargs -0 rm -f --
  • -l imprime los nombres de los archivos que coinciden con el patrón de búsqueda.
  • -rrealiza una búsqueda recursiva del patrón fooen el directorio dado .. Si esto no funciona, inténtalo -R.
  • -I(capital i) hace que se omitan los archivos binarios como los PDF.
  • -Z garantiza que los nombres de los archivos estén terminados en cero (es decir, nul-) para que un nombre que contenga espacios en blanco no se interprete de manera incorrecta (es decir, como nombres múltiples en lugar de uno).
  • xargs -0alimenta los nombres de archivo de grepa rm -f, separando las palabras por cero (nul) bytes (recuerde la -Zopción de grep).
  • --a menudo se olvida, pero es muy importante marcar el final de las opciones y permitir la eliminación de archivos cuyos nombres comienzan con -.

Si desea ver qué archivos están a punto de eliminarse, simplemente elimine la | xargs -0 rm -f --pieza y desactive la Zopción grep.

Otro usuario sugirió algo como lo siguiente, que no debe ejecutar porque no es seguro:

files=`grep foo * | cut -d: -f1`
rm -f $files         # unsafe, do not run it!

Si tengo archivos ImportantStuffque no quiero eliminar y que obsolete ImportantStuffcontienen foo, entonces pierdo ImportantStuff(¡y no obsolete ImportantStuff !) Cuando ejecuto este comando, porque $filesse rompe en espacios cuando se interpreta. Es peligroso poner una lista de nombres de archivo en una variable de shell escalar de esta manera.

Lekensteyn
fuente
17
$ find -type f -exec grep -q "foo" {} \; -exec echo rm -- {} \;

Esto busca de forma recursiva los archivos que contienen foo. El segundo -execsolo se ejecuta si el primero execsale con éxito, es decir, si grepcoincide. Ejecute en seco y elimine echosi la salida parece correcta.

O alternativamente

$ find -type f -exec grep -q "foo" {} \; -print

y

$ find -type f -exec grep -q "foo" {} \; -delete

según lo sugerido por Lekensteyn.

Adrian Frühwirth
fuente
44
... que se puede acortar a: find -type f -exec grep -q 'foo' {} \; -delete(las comillas {}son redundantes, findtambién puede eliminar archivos). Tenga en cuenta que grepacepta una expresión regular. Si desea buscar foo.bar, salga de esto o pase la -Fopción de tratar el patrón como literal.
Lekensteyn
alguna razón para usar -exec echo rm "{}" \;y no -delete?
vartec
1
@vartec No, lo usaría -delete. Es más fácil demostrar con el segundo -execy hacer eco en su lugar.
Adrian Frühwirth
1
Es más fácil escribir -print(o -lspara más verbosidad) que -exec echo rm "{}" \'. No hay necesidad de utilidades externas.
Lekensteyn
1
si usa rm {}, use rm - {}, para que los caracteres especiales en el nombre del archivo no se interpolen. Por ejemplo, toque '-rf /' en cualquier directorio donde tenga permisos de escritura ...
atk
1

Haría lo que Adrian dice:

Pero agregaría límites de palabras al foo para no eliminar accidentalmente archivos que contengan "comida" (a menos que esté borrando todo lo que contiene comida es lo que desea).

 $ find -type f -exec grep -q "\<foo\>" {} \; -delete

agudamente, redirigiría la salida antes de eliminar para poder revisar antes de eliminar:

 $ find -type f -exec grep -q "\<foo\>" > /tmp/list_of_files_to_delete
Petter H
fuente
Tan pronto como pueda publicar comentarios, debe publicar cosas como esas como comentarios.
FSMaxB
Sí, lo intenté primero pero luego me di cuenta de que todavía no tengo permitido publicar comentarios.
Petter H