Eliminar todos los archivos en un directorio cuyo nombre no coincida con una línea en una lista de archivos

9

Tengo un directorio con más de 1000 archivos. En un archivo de texto, tengo alrededor de 50 nombres de archivo, uno por línea. Me gustaría eliminar todos los archivos en el directorio cuyos nombres de archivo no se corresponden con una entrada en la lista. ¿Cuál es la mejor manera de hacer esto? Comencé un script de shell, pero no pude determinar el comando adecuado para determinar en el nombre de archivo que está en la lista. Gracias.

Nathan
fuente

Respuestas:

8

Me doy cuenta de que cualquier pregunta sobre cómo eliminar archivos debe tomarse con mucho cuidado. Mi primera respuesta fue demasiado apresurada. No tomé el hecho de que la lista de archivos podría estar mal formada para usarse con egrep. Edité la respuesta para reducir ese riesgo.

Eso debería funcionar para los archivos que no tienen espacio en el nombre:

Primero reconstruya su lista de archivos para asegurarse de que coincida con el nombre exacto del archivo:

sed -e 's,^,^,' -e 's,$,$,'  filelist  > newfilelist 

construir los comandos rm

cd your_directory
ls | egrep -vf newfilelist   | xargs -n 1 echo rm  >  rmscript

Compruebe si el script rm le conviene (puede hacerlo con "vim" o "less").
Luego realiza la acción:

sh -x rmscript

Si los archivos tienen espacios en su nombre (si los archivos tienen "el nombre, entonces esto no funcionará):

ls | egrep -vf newfilelist  | sed 's,^\(.*\)$,rm "\1",' > rmscript

¡por supuesto, la lista de archivos no debe estar en el mismo directorio!

EDITADO:

La lista de archivos de Nathan contenía nombres que coincidían con todos los archivos del directorio (como "html" coincide con "bob.html"). Entonces no se eliminó nada porque egrep -vfabsorbió toda la transmisión. Agregué un comando para poner un "^" y un "$" alrededor de cada nombre de archivo. Tuve la suerte de que la lista de archivos de Nathan era correcta. Si hubiera sido formateado con DOS con líneas terminadas CR-LF o con espacios adicionales, egrep no habría preservado ningún archivo y todos se habrían eliminado.

Emmanuel
fuente
Cuando ejecuto el comando de vista previa, aparece una línea con "rm". Cuando ejecuto el comando real, recibo un mensaje de error sobre los argumentos faltantes para rm. ¿Necesito una sintaxis especial para usar los resultados de ls | egrep en la entrada xargs?
Nathan
@Nathan primero debes cd a tu directorio. Sin sintaxis especial. lsproporciona los nombres de archivo de directorio, egrep -vf filelistfiltre sus 50 nombres de archivo. Me temo que borraste todos tus archivos.
Emmanuel
@Emamanuel Estoy ejecutando el comando desde el directorio que contiene los archivos que se eliminarán.
Nathan
@Nathan, ¿se eliminan todos tus archivos?
Emmanuel
No, todavía están allí.
Nathan
1

Preconstruir los argumentos para find:

{
  read -r
  keep=( -name "$REPLY" ) # no `-o` before the first one.
  while read -r; do
    keep+=( -o -name "$REPLY" )
  done
} < file_list.txt
find . -type f ! \( "${keep[@]}" \) -exec echo rm {} +

Usa las echopartes para ver qué se construiría. Retire las echopartes para ejecutarlo realmente.

Actualización: Demostración:

##
# Demonstrate what files exist for testing.
# Show their whitespace:
~/foo $ printf '"%s"\n' *
" op"
" qr"
"abc"
"def"
"gh "
"ij "
"k l"
"keep"
"m n"

##
# Show the contents of the "keep" file,
# Including its whitespace:
~/foo $ cat -e keep
keep$
abc$
gh $
k l$
 op$

##
# Execute the script:
~/foo $ { read -r; keep=( -name "$REPLY" ); while read -r ; do keep+=( -o -name "$REPLY" ); done } < keep
~/foo $ find . -type f ! \( "${keep[@]}" \) -exec rm {} +

##
# Show what files remain:
~/foo $ printf '"%s"\n' *
" op"
"abc"
"gh "
"k l"
"keep"
kojiro
fuente
este me gusta más, ya que elimina la necesidad de una lista de archivos anterior
eyoung100
+1 de mi parte, aunque no se trata muy bien con espacios. Quizás 'deberían agregarse algunas comillas simples ( ), es decir, keep=( -name \'"$REPLY"\' )y keep+=( -o -name \'"$REPLY"\' ).
Cristian Ciupitu
lo anterior es peligroso, porque puede eliminar archivos accidentalmente.
davidva
@CristianCiupitu no? Agregué una demostración que muestra que trata muy bien con espacios en blanco.
kojiro
@davidva ¿En qué circunstancias? Cada vez que automatiza la eliminación de cosas, corre el riesgo de cometer un error, pero dentro de los parámetros de la pregunta, creo que mi demostración demuestra que este enfoque es sólido.
kojiro
1

Con zsh:

mylist=(${(f)"$(<filelist)"})
print -rl -- *(.^e_'(($mylist[(Ie)$REPLY]))'_)

Lee las líneas de filelistuna matriz y luego usa calificadores / ecadena glob para glob / seleccionar solo los nombres de archivo que no están presentes en la matriz: .selecciona solo archivos regulares (agregue Dsi su lista contiene archivos de puntos) y los negados ^e_'expression'_seleccionan solo aquellos para que la expresión devuelve falso, es decir, si su nombre ( $REPLY) no es un elemento de la matriz .
Si está satisfecho con el resultado, reemplace print -rlcon rmpara eliminar realmente los archivos:

rm -- *(.^e_'(($mylist[(Ie)$REPLY]))'_)

Para seleccionar y eliminar archivos de forma recursiva, use el modificador */**glob con ${REPLY:t}glob:

rm -- */**(.^e_'(($mylist[(Ie)${REPLY:t}]))'_)
revs don_crissti
fuente
0

Si coloca el contenido del directorio en un archivo así:

cd <somedirectory>
ls >> filelist

Abra la lista de archivos con un editor de texto y elimine todos los archivos, excepto los que DESEA ELIMINAR . Eso está en negrita porque es el enfoque opuesto a la respuesta anterior

Prueba esto:

while read p || [[ -n $p ]]; 
echo $p
done < filelist

Si ve su lista de salida de archivos a la pantalla, reemplace echo con rm -v, así:

while read p || [[ -n $p ]]; 
rm -v $p
done < filelist
eyoung100
fuente
0

Ejecute el siguiente script.

  1. Inicialmente estoy encontrando todos los archivos que están presentes dentro del directorio y almacenando la salida en otro archivo all_files.
  2. Tenemos un archivo que tiene la lista de archivos que NO deben eliminarse ( not_to_be_deleted_files).
  3. Estoy agregando los nombres de archivo not_to_be_deleted_filesy files_to_be_deletedal final de, not_to_be_deleted_filesya que necesitamos estos 2 archivos.
  4. Ahora, estoy encontrando los archivos que deben eliminarse utilizando el joincomando de Linux y redirigiendo la salida al files_to_be_deleted archivo.
  5. Ahora, en el ciclo while final, estoy leyendo todos los nombres de archivo files_to_be_deletedy eliminando los archivos mencionados en ese nombre de archivo.

El guión es el siguiente.

find /home/username/directory -type f | sed 's/.*\///' > all_files
echo all_files >> not_to_be_deleted_files
echo not_to_be_deleted_files >> not_to_be_deleted_files
echo files_to_be_deleted >> not_to_be_deleted_files
join -v 1 <(sort all_files_listed) <(sort files_not_to_be_deleted) >   files_to_be_deleted
while read file
rm  "$file"
done < files_to_be_deleted

PD : Probablemente, si deseas que esto se guarde como un script y lo ejecutes, también puedes agregar el nombre del script usando echo scriptname >> not_to_be_deleted_files.

Aunque no es obligatorio, prefiero hacerlo porque no habrá arrepentimientos más adelante. Probé un pequeño conjunto de archivos y funcionó en mi sistema. Sin embargo, si quiere estar seguro, intente testprimero en un directorio y luego elimine los archivos en el directorio original.

Ramesh
fuente
0
  • Utilice la lista como fuente para mover todos los archivos de la lista a un directorio de guardado nuevo, nuevo y vacío.
  • Compare la cantidad de archivos en la lista y la cantidad de archivos guardados.
  • Si ambos coinciden, elimine todos los archivos no guardados con su método favorito.
  • Mueva los archivos guardados de nuevo.
usuario desconocido
fuente
0

¡Fui por un enfoque más seguro y mucho más rápido porque tenía 18,000 archivos en la lista! Necesitaba limpiar imágenes en una gran instalación de Drupal.

Eliminar todos los archivos que no están en la lista es lo mismo que conservar solo los que están en la lista. Así que decidí copiar los archivos de la lista a otra ubicación, pero copiar 20 GB de archivos ocuparía demasiado espacio y también sería muy lento. Entonces, el truco es copiar los archivos como hardlinks, en su lugar, usando la -lopción de cp. Esto casi no ocupa espacio y es muy rápido. Además, como necesitaba preservar la estructura del directorio, utilicé la --parentsopción.

Aquí hay un extracto de mi lista de archivos:

1px.png
misc/feed.png
modules/file/icons/x-office-presentation.png
modules/file/icons/x-office-spreadsheet.png
newsletter.png
sites/all/libraries/ckeditor/plugins/smiley/images/devil_smile.png
sites/all/libraries/ckeditor/plugins/smiley/images/regular_smile.png
sites/default/files/009313_PwC_banner_CBS_Observer_180x246px.jpg

Entonces, una línea de ejemplo sería, con temp como destino:

cp -l --parents 'misc/feed.png' temp

Esto creará esta estructura:

temp
  misc
    feed.png

Tenga en cuenta que el destino debe estar en el mismo sistema de archivos que la fuente para que funcionen los enlaces duros.

El siguiente paso es construir el script:

sed -e "s,^,cp -l --parents '," -e "s,$,' /some/where/temp," filelist > newfilelist

Ahora, suponiendo que ya haya creado el directorio vacío / some / where / temp, puede copiar los archivos de esta manera:

sh newfilelist 2> missing_files

Tenga en cuenta cómo terminan los errores missing_files. ¡La ventaja adicional de este enfoque es que obtendrá una lista de archivos de la lista original que en realidad no existen!

Después de ejecutar el script, temp contendrá solo aquellos archivos que están en la lista de archivos, pero sin eliminar nada y sin ocupar espacio adicional. Si está satisfecho con el resultado, puede eliminar todos los archivos originales, incluidas las subcarpetas.

Finalmente, mueva los archivos y carpetas de temp nuevamente a la ubicación original.

Para los 18,000 archivos, solo tomó unos segundos.

marlar
fuente
0

Seguro, simple.

cd al directorio

Crea un directorio temporal.

mv *.yourExlusionSelector.* ./temp
rm *
mv ./temp ./
rm -rf ./temp

hecho.

paradisaeidae
fuente
Bienvenido al sitio. Si bien su enfoque funcionará si los nombres en la lista mencionada por el OP son el resultado de una simple coincidencia de patrones, lo cual puede ser el caso, tenga en cuenta que el OP declaró que los nombres de archivo a excluir se almacenan en un archivo específico; es posible que desee expandir su respuesta para leer los patrones de exclusión de ese archivo en lugar de confiar en un patrón estático, o tener que copiar y copiar potencialmente múltiples patrones en la consola.
AdminBee