¿Cambiar el nombre de un montón de archivos con la fecha de modificación y la marca de tiempo al final del nombre del archivo?

¿Cambiar el nombre de un montón de archivos con la fecha de modificación y la marca de tiempo al final del nombre del archivo?

Entonces, digamos, tengo un directorio con un montón de archivos como g.txt, donde g.txt se modificó por última vez, digamos, el 20 de junio de 2012.

¿Cómo cambiaría el nombre por lotes de todos los archivos (como g.txt) con la fecha de última modificación del 20 de junio de 2012 al final?

Respuesta1

Aquí hay una versión de la frase de Goldschrafe que:

  • no usa estadística

  • funciona con versiones anteriores de GNU date

  • hace frente correctamente a cualquier espacio en los nombres de archivos

  • también funciona con nombres de archivos que comienzan con un guión

    for f in *; do mv -- "$f" "$f-$(date -r "$f" +%Y%m%d)"; done


Actualización 2021-03-20

Mi respuesta a esta pregunta me ha estado molestando durante años (bueno, sólo cuando la recuerdo, en días como hoy, cuando recibe otro voto positivo), así que finalmente la estoy actualizando. Mi respuesta original anterior todavía funciona, pero la respuesta actualizada a continuación es mejor.

Comocualquieroperación de cambio de nombre de archivo por lotes, esto debe hacerse con elperla renameutilidad, no con algún shell for loop torpe.

La utilidad de cambio de nombre de Perl es efectivamente un lenguaje de secuencias de comandos especializado que le permite usar CUALQUIER código Perl para cambiar el nombre de archivos, desde simples s/search/replace/operaciones de expresión regular (que son suficientes para la mayoría de las tareas de cambio de nombre) hasta secuencias de comandos complejas de varias líneas.

p.ej

rename -n 'BEGIN {use Date::Format};
           die $! unless -f $_;
           next if (m/-\d{8}$/);
           my $ts=(stat($_))[9];
           my $dt=time2str("%Y%m%d",$ts);
           s/$/-$dt/;' *.txt

Esto requiere solo perl y el Date::Formatmódulo (un módulo que es tan útil que debería instalarse en cualquier sistema con perl. En mi opinión, junto con el Date::Parsemódulo del autor Graham Barr,deberíaser parte de la biblioteca de módulos principales de Perl, pero no lo es, por lo que tendrá que instalarlo con cpanun paquete de distribución como el paquete de Debian libtimedate-perl).

Por cierto, este script omite cualquier archivo que parezca que ya tiene una fecha (es decir, 8 dígitos) al final del nombre del archivo.

o, para una versión más elegante que coloca la fecha antes del sufijo del archivo (si corresponde):

rename -n 'BEGIN {use Date::Format; use File::Basename};
           die $! unless -f $_;
           my ($filename,$dirs,$suffix) = fileparse($_,qr/\.[^.]*/);
           next if (m/-\d{8}${suffix}$/);
           my $ts=(stat($_))[9];
           my $dt=time2str("%Y%m%d",$ts);
           s/${suffix}$/-${dt}${suffix}/;' *.txt

Esta versión no tiene requisitos adicionales porque el File::Basenamemódulo se ha incluido como un módulo central estándar con Perl desde que tengo uso de razón (al menos una década, probablemente más).

Nota:Ambos renamescripts anteriores utilizan la opción "ejecución en seco" de rename -n(también conocida como --nono) para que los resultados puedan probarse/simularse antes de aplicarse. Elimine -n(o reemplácelo con -vuna salida detallada) cuando esté seguro de que hace lo que desea.

También tenga en cuenta:Al igual que con cualquier otro renamescript Perl, esto puede cambiar el nombre de los archivos proporcionados en la línea de comando y/o desde la entrada estándar. por ejemplo, para cambiar el nombre de todos los archivos .txt en el directorio actual y todos los subdirectorios:

find . -type f -iname '*.txt' -print0 | 
   rename -0 --nofullpath -n '..........'

Por cierto, he usado renamela opción --nofullpath (también conocida como -d, --filenmame, --nopath) aquí para asegurarme de que cambie el nombre solo de la parte del nombre de archivo de cualquier ruta de archivo encontrada. No es necesario en este caso particular (porque los scripts de cambio de nombre de ejemplo solo cambian el final del nombre del archivo) pero generalmente es una buena idea cuando no desea cambiar el nombre de la ruta además del nombre del archivo (por ejemplo, un script de cambio de nombre como 's/ //g'para quitar los espacios de los nombres de archivos intentarían eliminar los espacios en la ruta, así como el nombre del archivo sin --nofullpath, probablemente provocando que falle con un error).

Finalmente:No confunda el script de cambio de nombre de Perl (también conocido como File::Rename, o a veces llamado prenameen Fedora y RedHat, o perl-rename) con cualquier otro programa llamado cambio de nombre. SoloEsta utilidad de cambio de nombre basada en Perl puede cambiar el nombre de archivos usando código Perl arbitrario como se muestra arriba; cualquier otra utilidad de cambio de nombre tendrá capacidades diferentes y opciones de línea de comandos diferentes e incompatibles.

Puedes comprobar si tienes instalado el cambio de nombre correcto:

$ rename -V
/usr/bin/rename using File::Rename version 1.13, File::Rename::Options version 1.10

Es posible que el ejecutable se llame prenameo perl-renameo file-renameen su sistema, así que pruebe -Vcon ellos y ajuste los ejemplos anteriores para usar el nombre correcto del ejecutable.

Respuesta2

Una sola línea de Bash, rápida y sucia, para cambiar el nombre de todos los archivos (globulados) en el directorio actual de filename.txta filename.txt-20120620:

for f in *; do mv -- "$f" "$f-$(stat -c %Y "$f" | date +%Y%m%d)"; done

Un nerd emprendedor de Bash encontrará algún caso límite para romperlo, estoy seguro. :)

Obviamente, esto no hace cosas deseables como comprobar si un archivo ya tiene algo parecido a una fecha al final.

Respuesta3

Obligatorio zsh one-liner (sin contar la carga única de componentes opcionales):

zmodload zsh/stat
autoload -U zmv
zmv -n '(*)' '$1-$(stat -F %Y%m%d +mtime -- $1)'

Usamos el statincorporado delzsh/statmódulo, y elzmvFunción para cambiar el nombre de los archivos. Y aquí tenéis un extra que sitúa la fecha anterior a la prórroga, si la hubiera.

zmv -n '(*)' '$1:r-$(stat -F %Y%m%d +mtime -- $1)${${1:e}:+.$1:e}'

Respuesta4

Aquí hay una versión del oneliner de cas (basado en el oneliner de goldschrafe) ampliado conidempotencia,

es decir, extendido a archivos de prefijo con fecha, hora yhacer esto solo para aquellos que aún no tienen el prefijo de fecha y hora.

Caso de uso: útil si agrega nuevos archivos al directorio y desea agregar un prefijo de fecha y hora a aquellos que aún no lo tienen.

for f in * ; do
  if [[ "$f" != ????-??-??' '??:??:??' - '* ]]; then
    mv -v -- "$f" "$(date -r "$f" +%Y-%m-%d' '%H:%M:%S) - $f" ;
  fi;
done

información relacionada