Eliminar archivos que no contengan una cadena específica

Quiero encontrar los archivos que no contienen una cadena específica (en un directorio y sus subdirectorios) y eliminar esos archivos. ¿Como puedo hacer esto?

preguntado el 01 de julio de 12 a las 08:07

@SivaCharan sí... de la existencia :) -

Por eliminar quiero decir: eliminar -

7 Respuestas

Lo siguiente funcionará:

find . -type f -print0 | xargs --null grep -Z -L 'my string' | xargs --null rm

Primero usará find para imprimir los nombres de todos los archivos en el directorio actual y cualquier subdirectorio. Estos nombres se imprimen con un terminador nulo en lugar del separador de nueva línea habitual (intente canalizar la salida a od -c para ver el efecto de la -print0 argumento.

Entonces el --null parámetro para xargs le dice que acepte entradas terminadas en nulo. xargs entonces llamaré grep en una lista de nombres de archivos.

El -Z argumento para grep funciona como el -print0 argumento para find, por lo que grep imprimirá sus resultados terminados en cero (razón por la cual la llamada final a xargs necesita una --null opción también). los -L argumento para grep causas grep para imprimir los nombres de archivo de esos archivos en su línea de comando (que xargs ha añadido) que no coincide con la expresión regular:

mi cuerda

Si desea una coincidencia simple sin magia de expresión regular, agregue el -F opción. Si desea expresiones regulares más poderosas, dé un -E argumento. Es un buen hábito usar comillas simples en lugar de comillas dobles, ya que esto lo protege contra cualquier magia de shell que se aplique a la cadena (como la sustitución de variables)

Finalmente llamas xargs de nuevo para deshacerte de todos los archivos que hayas encontrado con las llamadas anteriores.

El problema de llamar grep directamente desde el find comando con el -exec el argumento es que grep luego se invoca una vez por archivo en lugar de una vez por un lote completo de archivos como xargs lo hace. Esto es mucho más más rápido si tiene muchos archivos. Tampoco caigas en la tentación de hacer cosas como:

rm $(some command that produces lots of filenames)

Siempre es mejor pasárselo a xargs ya que esto conoce los límites máximos de la línea de comandos y llamará rm varias veces cada vez con tantos argumentos como sea posible.

Tenga en cuenta que esta solución habría sido más sencilla sin la necesidad de lidiar con archivos que contienen espacios en blanco y líneas nuevas.

Alternativamente

grep -r -L -Z 'my string' . | xargs --null rm

funcionará también (y es más corto). los -r argumento para grep hace que lea todos los archivos en el directorio y descienda recursivamente a cualquier subdirectorio). Utilizar el find ... acérquese si también desea realizar otras pruebas en los archivos (como la edad o los permisos).

Tenga en cuenta que cualquiera de los argumentos de una sola letra, con un solo guión introductor, se puede agrupar (por ejemplo, como -rLZ). Pero nótese también que find no usa las mismas convenciones y tiene argumentos de varias letras introducidos con un solo guión. Esto se debe a razones históricas y nunca se ha solucionado porque habría roto demasiados guiones.

Respondido el 07 de diciembre de 17 a las 17:12

De cualquier forma, si queremos comprobar una lista de cadenas como grep -r -L -Z 'Astring' OR 'Bstring' OR 'Cstring' * | xargs --null rm ? - El-Burritos

Puede usar la forma egrep de grep y luego buscar cadenas alternativas como esta: egrep ... 'Astring|Bstring|Cstring' ... - Nick

@ user1394 ¿Qué problema ve? - Nick

xargs: illegal option -- - - user1394

@user1394 ¿Puede mostrarme lo que está escribiendo y la respuesta que ve? Nick

GNU grep y bash.

grep -rLZ "$str" . | while IFS= read -rd '' x; do rm "$x"; done

Utilizar find solución si se necesita portabilidad. Esto es un poco más rápido.

Respondido 01 Jul 12, 09:07

@ Peter.O Extraño, no puedo reproducir eso. Aparece si se usa -r no tiene más remedio que usar por defecto los archivos a menos que - se da explícitamente. Todavía, . es probablemente una buena idea. Lo agregué. - ormaaj

Ya eliminé mi comentario original cuando agregaste el ., como sin duda habrás visto, pero también estoy un poco desconcertado, porque 'man grep' muestra [FILE ...] para la última opción... pero eso es definitivamente lo que sucede aquí (es decir, esperando la entrada, sin .); GNU grep 2.5.4 - Pedro.O

El valor por defecto "." para grep -r se agregó en grep 2.11, bastante reciente. Y GNU no respeta mucho las páginas man. - alan curry

Ah, 2.12 aquí. 2.5.4 es el más antiguo disponible en mi repositorio. - ormaaj

EDIT: Así es como tú NO DEBERÍA ¡hacer esto! se da la razon aquí. ¡Gracias a @ormaaj por señalarlo!

find . -type f | grep -v "exclude string" | xargs rm

Nota: grep el patrón coincidirá con la ruta completa del archivo del directorio actual (ver find . -type f salida)

Respondido 02 Jul 12, 01:07

Downvote no era yo, pero FYI, probablemente se debió a xargs - ormaaj

@ormaaj Dios mío! Solía ​​​​usar esto con bastante frecuencia (xx;) Gracias por señalarlo. - rodion

este comando es realmente increíble, funciona rápido y perfectamente - edwin reyes

Una posibilidad es

find . -type f '!' -exec grep -q "my string" {} \; -exec echo rm {} \;

Puedes eliminar el echo si la salida de esta vista previa parece correcta.

El equivalente con -delete is

find . -type f '!' -exec grep -q "user_id" {} \; -delete

pero luego no obtienes la buena opción de vista previa.

respondido 14 mar '20, 04:03

Esto no funciona para mí. Puedo ver que el comando rm se está ejecutando en la línea de comandos, pero no se elimina nada después de finalizar el comando. Todos los archivos existen todavía. Revisé manualmente los archivos y vi que algunos de ellos no contienen la cadena... - Juez

Parece haber cierta confusión sobre si quería identificar archivos sin una determinada cadena en su nombre o en su contenido. Esta respuesta (con -v en lugar de -q) estaría mirando los nombres de archivo. Mi respuesta mira el contenido. - alan curry

@Hakim, el comando hace eco en lugar de eliminarlo. Es una buena práctica para tratan antes de borrar. Si los archivos enumerados son correctos, elimine la palabra echo. - lev levitsky

Eso encontraría archivos que contienen una cadena dada ... no NOT containing. por eso doy -1, porque esa respuesta podría arruinar la vida de alguien. Estoy marcando también. - Trueno relámpago

@Flash: realmente, ¿qué tan difícil es agregar ! a find¿Los argumentos para invertir el sentido? No es como si alguien copiara ciegamente una respuesta sin tratar de entender qué hace. Y echo rm difícilmente arruina la vida de nadie. - Toby Speight

Puedo pensar en algunas maneras de abordar esto. Aquí hay uno: busque y grep para generar una lista de archivos sin coincidencia, y luego xargs rm ellos.

find yourdir -type f -exec grep -F -L 'yourstring' '{}' + | xargs -d '\n' rm

Esto supone herramientas GNU (grep -L y xargs -d no son portátiles) y, por supuesto, no hay nombres de archivo con saltos de línea en ellos. Tiene la ventaja de no ejecutar grep y rm una vez por archivo, por lo que será razonablemente rápido. Recomiendo probarlo con "echo" en lugar de "rm" solo para asegurarse de que selecciona los archivos correctos antes de desatar la destrucción.

Respondido 01 Jul 12, 09:07

Este no está haciendo xargs bien tampoco Si usa xargs, -0 es la única manera. - ormaaj

-d '\n' es una forma lo suficientemente buena hasta que obtenga un nombre de archivo con una nueva línea. Deshabilita la mayor parte de la estupidez de xargs, como lo hace -0. Sin embargo, es bueno aprender sobre grep -Z. - alan curry

un nombre de archivo con una nueva línea en él? ¿Qué tal el tipo con un gato en el teclado? ¡Él no puede escribir un comando largo como este! ar ya, eso es una locura. pero puedes encontrar eso en youtube. - J-16 SDIZ

sí, está bien si solo hay nombres de archivo cuerdos. - ormaaj

Está bien. Esto funciona bien para mí. Eliminé los espacios en los nombres de archivo y verifiqué este script. Gracias Alan - Juez

Para eliminar archivos que no contengan una cadena específica:

Intento:

Para usarlos, habilite la opción de shell extglob de la siguiente manera:

shopt -s extglob

Y simplemente elimine todos los archivos que no tengan la cadena "arreglar":

rm !(*fix*)

Si no desea eliminar todos los archivos que no tienen los nombres "fix" y "class":

rm !(*fix*|*class*)

Zsh:

Para usarlos, habilite la opción extendida glob zsh shell de la siguiente manera:

setopt extended_glob

Elimine todos los archivos que no tengan la cadena, en este ejemplo "arreglar":

rm -- ^*fix*

Si no desea eliminar todos los archivos que no tienen los nombres "fix" y "class":

rm -- ^(*fix*|*class*)

Es posible usarlo para extensiones, solo necesita cambiar la expresión regular: (.Código Postal) , (.doc), etc

Aquí están las fuentes:

https://www.tecmint.com/delete-all-files-in-directory-except-one-few-file-extensions/

https://codeday.me/es/qa/20190819/1296122.html

Respondido el 01 de diciembre de 19 a las 14:12

Esto funcionó para mí, puede eliminar el -f si está de acuerdo con eliminar directorios.

myString="keepThis"
for x in `find  ./`
    do if [[ -f $x && ! $x =~ $myString ]]
        then rm $x
    fi
done

respondido 22 nov., 21:14

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.