Secuencia de commands para eliminar files que no coinciden con ciertos nombres de file

Tengo una carpeta con 500,000 imágenes, clasificadas en subcarpetas por año y mes. Me gustaría crear un script que haga esto:

Si el nombre del file no coincide con ninguno de los nombres de file en names.log , elimine el file. names.log contendría nombres de file, como:

 image1.jpg photo3.jpg networkingcar.jpg balloon2323.jpg 

etc … tiene cerca de 10,000 nombres de files que quiero MANTENER

Tengo PHP y Python en el server, pero no estoy seguro de qué sería lo mejor para esto. No he hecho ninguna secuencia de commands antes. ¿Podría alguien ser tan amable de darme un fragment de código que logre eso y dejarme saber cómo ejecutarlo? O tal vez esto se puede lograr con un command en su lugar?

Solutions Collecting From Web of "Secuencia de commands para eliminar files que no coinciden con ciertos nombres de file"

Esto es bastante fácil en Python con os.walk . Advertencia, código no probado. Supongo que la list de nombres contiene un nombre por línea con

 #!/usr/bin/python2 import os names_file = open('names.log') names = set(line.rstrip('\n') for line in names_file.readlines()) names_file.close() for root, dirs, files in os.walk('/path/to/top/directory'): for name in files: path = os.path.join(root, name) if os.path.isfile(path): if name not in names: print path #os.remove(path) # uncomment this line if you're happy with the set of files to remove 
 find -name '*.jpg' -print0 | grep -zZ -vf name.log | xargs -0 COMMAND 

reemplace COMMAND por ls -l y si lo desea por rm

Editar : El command presentado trata a nombre.log como un set de expresiones regulares. @terdon recordó tha name.log es una list de nombres de files.

Si los nombres de file utilizan los caracteres "normales" usuales, esto probablemente sea suficiente, pero pueden popup problemas si:

  1. Los nombres de file / regexp incluyen caracteres inusuales como [ , ] , etc. (en este caso, puede no eliminar algunos files e incluso puede eliminar algunos files cuyo nombre se encuentra en name.log ). Para evitar esto, podemos usar grep -F o proteger el carácter especial en name.log .
  2. Regexp coincide con una subcadena de nombres de file (en este caso, algunos files no se eliminarían; a.jpg coincidiría con todas las imágenes que terminan en "a", como camera.jpg , banana.jpg ).

Para el caso 2, para la situación de prefijos, – podemos agregar "/" en el comienzo de la expresión regular.

 sed 's!^!/!' name.log > new.log find -name '*.jpg' -print0 | grep -F -zZ -vf new.log | xargs -0 COMMAND 

o incluso

 find -name '*.jpg' -print0 | grep -zZFvf <(sed 's!^!/!' name.log) | xargs COMMAND 

para el caso 2, la situación del sufijo es less importante porque los files de image tienen extensiones. Para resolver este caso correctamente, necesitamos decir que "no hay nada después del nombre de file": necesitamos expresiones regulares, y los caracteres especiales (por ejemplo, [ ] ) en los nombres de files deben estar protegidos.

 sed -re 's!([].[])!\\\1!g; s!.*!/&$!' name.log > new.log find -name '*.jpg' -print0 | grep -zZ -vf new.log | xargs -0 COMMAND 

Esto es realmente fácil con pax . Tiene una noción de una opción -substitution que puede cambiar los nombres de los files a medida que se escriben. También puede especificar más de uno de los arguments de sustitución. Y, lo más relevante aquí, es que los miembros seleccionados solo tienen tantos arguments de implementación implementados como sean necesarios para hacer una coincidencia con éxito, pero cualquier sustitución que dé como resultado un nombre de file nulo da como resultado que no se select el file coincidente.

Demostrar:

 mkdir test; cd test touch match nomatch pax -ws '|^.*/match$|&|' -s '|.*||' ./ | pax -v 

Lo anterior hace y cambia a un directory ./test , crea dos files, luego -w rites un file tar a un canal w / pax cuyo contenido contiene una segunda list pax -v . Las impresiones de arriba:

 -rw-r--r-- 1 mikeserv mikeserv 0 Feb 22 11:40 ./ 

… porque ./match se ./match antes de la sustitución final que sustituye a todos los caracteres en cualquier nombre de file.

Y con pax no tiene que copyr el contenido de un file en su file, puede usar -rwl que es una operación de copy que crea -rwl .

Entonces, si su file se llamaba paxscript y parecía …

 cd -- "$1" pax -rwvl \ -s '|^.*/image1\.jpg$|&|' \ -s '|^.*/photo3\.jpg$|&|' \ -s '|^.*/networkingcar\.jpg$|&|' \ -s '|^.*/balloon2323\.jpg$|&|' \ -s '|.*||' ./ ../"${1##*/}.mirror" cd - >/dev/null 

… y luego lo corrió como …

 . ./paxscript "$targetdir" 

"$targetdir" un espejo de "$targetdir" en su directory principal que contiene solo enlaces duros a los nombres de file que desea emparejar. A continuación, puede verificar que los resultados son de su agrado antes de rm -rf "$targetdir" y deshacerse de todos los nombres de ruta que no desee.


Si cumple con bash me gustaría ofrecer el siguiente algorithm (podría realizarse en cualquier lengua de scripting):

  1. Lista de compilation de los files presentes: find /path_to_folder -name "*.jpg" -fprint files.tmp
  2. Ordenar files.tmp y name.log que compararlos por comm -23 files.tmp name.log
  3. Pase la list de files únicos para el command files.tmp to rm

Tenga en count la ruta de los files: en los files files.tmp y name.log puede ser el mismo (completo o relativo a una carpeta). El separador de nombre de file para name.log en el caso sería newline .