
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 rename
utilidad, 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::Format
mó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::Parse
mó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 cpan
un 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::Basename
mó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 rename
scripts 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 -v
una salida detallada) cuando esté seguro de que hace lo que desea.
También tenga en cuenta:Al igual que con cualquier otro rename
script 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 rename
la 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 prename
en 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 prename
o perl-rename
o file-rename
en su sistema, así que pruebe -V
con 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.txt
a 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 stat
incorporado delzsh/stat
módulo, y elzmv
Funció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