Busque archivos con nombres similares, elimine los más antiguos, cambie el nombre de los más recientes

Busque archivos con nombres similares, elimine los más antiguos, cambie el nombre de los más recientes

Tengo esta situación en la que hay muchos archivos con nombres similares (pero todos siguen un patrón) en diferentes subcarpetas.

file1
file1 (Copy)
/folder1/file2.txt
/folder1/file2 (Copy).txt
/folder1/file3.png
/folder1/file3 (Copy).png

Cada archivo está en la misma carpeta de su copia y tiene la misma extensión, la diferencia es que tiene (Copy)al final del nombre

Quiero obtener todos estos archivos y eliminar el más antiguo, luego eventualmente cambiar el nombre del archivo, por ejemplo, file1 (Copy)a file1(es decir, eliminar el (Copy)sufijo) si es necesario cambiarle el nombre.

Estaba pensando en usar findy mvpero no estoy seguro de cómo decirle que mueva el más reciente.

Respuesta1

Extendidofind+bashsolución (también necesita la implementación GNU de stat):

find . -type f -name "* (Copy).*" -exec bash -c 'p="${0%/*}"; bn="${0##*/}"; 
        main_bn="${bn/ (Copy)/}"; 
        if [ -f "$p/$main_bn" ]; then 
           t_copy_file=$(stat -c %Y "$0"); t_main_file=$(stat -c %Y "$p/$main_bn"); 
           if [[ $t_copy_file -gt $t_main_file ]]; then 
               mv "$0" "$p/$main_bn"; 
           else
               rm "$0"; 
           fi; 
        fi' {} \;

  • p="${0%/*}"- ruta de archivo/ruta con nombre base recortado
  • bn="${0##*/}"- nombre base del archivo
  • main_bn="${bn/ (Copy)/}"- eliminar (Copy)la subcadena del nombre base para obtener elprincipal/comúnnombre base
  • if [ -f "$p/$main_bn" ]- Si elprincipal/originalEl archivo existe (y se descubre que es un archivo normal después de la resolución del enlace simbólico).
    • t_copy_file=$(stat -c %Y "$0")- obtener la hora de la última modificación encontrada"Copiar"archivo
    • t_main_file=$(stat -c %Y "$p/$main_bn")- obtener la hora de la última modificación deoriginalarchivo
    • if [[ $t_copy_file -gt $t_main_file ]]- Si el"Copiar"El archivo es el más reciente: muévalo aloriginaluno (hazlooriginal) conmv "$0" "$p/$main_bn"
    • de lo contrario - eloriginalel archivo es el reciente, eliminando "Copiar"archivo conrm "$0"

O un poco más corto con -ntel operador de prueba de archivos ( [ new­er­file –nt olderfile ]verifique si newerfilese cambió más recientemente que olderfile, o si newerfileexiste y olderfileno):

find . -type f -name "* (Copy).*" -exec bash -c 'p="${0%/*}"; bn="${0##*/}"; 
        main_bn="${bn/ (Copy)/}"; 
        if [ -f "$p/$main_bn" ]; then 
           if [ "$0" -nt "$p/$main_bn" ]; then 
               mv "$0" "$p/$main_bn"; 
           else
               rm "$0"; 
           fi; 
        fi' {} \;

Respuesta2

Puede ser más fácil con zsh:

setopt extendedglob # best in ~/.zshrc
for file (./**/?*" (Copy)"*(ND.)) {
  base=$file:h/${${file:t}/" (Copy)"}}
  [[ ! -f $base || -L $base ]] ||
    if [ $file -nt $base ]; then
      mv $file $base
    else
      rm -f $file
    fi
}

Es posible que desees comprobar primero que no haya file (Copy) (Copy).txtarchivos.

  • **/: cualquier nivel de subdirectorio
  • N:globo nuloexpandirse a nada si no hay ninguna coincidencia en lugar de generar un error
  • D: incluye archivos ocultos ( Darchivos ot) y desciende a directorios ocultos.
  • .: solo incluyeregulararchivos (sin directorio, quince, dispositivo, enlace simbólico...)
  • $file:h:cabezadel archivo (parte del directorio), como encsh
  • $file:t:cola(parte del nombre de archivo)
  • ${var/pattern/replacement}, aquí sin reemplazo
  • [[ ! -f $base || -L $base ]] ||...omita archivos o enlaces simbólicos no normales (incluso si apuntan a archivos normales) como medida de seguridad.
  • [ $file -nt $base ]: devuelve verdadero si $filese modificó por última vezdespués $base(o $baseno es accesible, no deberíamos pasar siguiendo la verificación anterior).

información relacionada