¿Cambiar el nombre de un grupo de archivos con fecha y hora modificada al final del nombre de archivo?

14

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

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

InquilineKea
fuente

Respuestas:

13

Rápido y sucio Bash one-liner para renombrar todos los archivos (globalizados) 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 emprendedor Bash nerd encontrará algún caso de borde para romperlo, estoy seguro. :)

Obviamente, esto no hace cosas deseables como verificar si un archivo ya tiene algo que parece una fecha al final.

jgoldschrafe
fuente
2
+1, se ve bien. puedes hacerlo un poco más robusto usando '-' como el primer argumento para mv. guardias contra filenaes comenzando con '-'
cas
55
¿Qué tipo de dateimplementación es esa? Mi GNU dateno parece manejar la entrada.
manatwork
coreutils 8.4 en RHEL 6.
jgoldschrafe
2
@jgoldschrafe, ¿estás seguro de que el código funciona correctamente para ti? pastebin.com/nNYubf3A
manatwork
55
buena captura manatwork. mi fecha GNU 8.13 tampoco admite la lectura de stdin. Es compatible con el uso del tiempo de modificación de un archivo con "-r", por ejemplo, "fecha +% Y% m% d -r $ f", por lo que ni siquiera se necesita estadística en este caso particular.
cas
18

Aquí hay una versión del one-liner de goldschrafe que:

  • no usa stat
  • funciona con versiones anteriores de la fecha GNU
  • hace frente correctamente a cualquier espacio en los nombres de archivo
  • también hace frente a los nombres de archivo que comienzan con un guión

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

cas
fuente
1
Debe hacerlo date -r "$f" +%Y%m%do no funcionará si POSIXLY_CORRECTestá en el medio ambiente. En general, las opciones deben ir antes que otros argumentos.
Stéphane Chazelas
esta debería ser la "respuesta correcta"
usuario no válido
Por supuesto que no necesitas los frenos "${f}".
G-Man dice 'Restablece a Monica' el
pero, ¿cómo lo haría de tal manera que las fechas que anteponemos, por ejemplo, "nombre de archivo AMD"
timebandit
2

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 del zsh/statmódulo y la zmvfunción para cambiar el nombre de los archivos. Y aquí hay un extra que coloca la fecha antes de la extensión, si corresponde.

zmv -n '(*)' '$1:r-$(stat -F %Y%m%d +mtime -- $1)${${1:e}:+.$1:e}'
Gilles 'SO- deja de ser malvado'
fuente
1

Como entendí, no sabemos de antemano cuál es la fecha de modificación. Por lo tanto, necesitamos obtenerlo de cada archivo, formatear la salida y cambiar el nombre de cada archivo de manera que incluya la fecha de modificación en los nombres de archivo.

Puede guardar este script como algo así como "modif_date.sh" y hacerlo ejecutable. Lo invocamos con el directorio de destino como argumento:

modif_date.sh txt_collection

Donde "txt_collection" es el nombre del directorio donde tenemos todos los archivos que queremos renombrar.

#!/bin/sh

# Override any locale setting to get known month names
export LC_ALL=c
# First we check for the argument
if [ -z "$1" ]; then
    echo "Usage: $0 directory"
    exit 1
fi

# Here we check if the argument is an absolute or relative path. It works both ways
case "${1}" in
  /*) work_dir=${1};;
  *) work_dir=${PWD}/${1};;
esac

# We need a for loop to treat file by file inside our target directory
for i in *; do
    # If the modification date is in the same year, "ls -l" shows us the timestamp.
    # So in this case we use our current year. 
    test_year=`ls -Ggl "${work_dir}/${i}" | awk '{ print $6 }'`
    case ${test_year} in *:*) 
        modif_year=`date '+%Y'`
        ;;
    *)
        modif_year=${test_year}
        ;;
    esac
    # The month output from "ls -l" is in short names. We convert it to numbers.
    name_month=`ls -Ggl "${work_dir}/${i}" | awk '{ print $4 }'`
    case ${name_month} in
            Jan) num_month=01 ;;
            Feb) num_month=02 ;;
        Mar) num_month=03 ;;
        Apr) num_month=04 ;;
        May) num_month=05 ;;
        Jun) num_month=06 ;;
        Jul) num_month=07 ;;
        Aug) num_month=08 ;;
        Sep) num_month=09 ;;
        Oct) num_month=10 ;;
        Nov) num_month=11 ;;
        Dec) num_month=12 ;;
        *) echo "ERROR!"; exit 1 ;;
    esac
    # Here is the date we will use for each file
    modif_date=`ls -Ggl "${work_dir}/${i}" | awk '{ print $5 }'`${num_month}${modif_year}
    # And finally, here we actually rename each file to include
    # the last modification date as part of the filename.
    mv "${work_dir}/${i}" "${work_dir}/${i}-${modif_date}"
done
Alinear
fuente
1
lea la página de manual de stat (1) para descubrir cómo puede reducir su script en aproximadamente 3/4 ... la mayor parte de lo anterior es reinventar la rueda. en particular, 'stat -c% Y' le dará el tiempo de modificación de un archivo en segundos desde la época (1970-01-01 00:00:00). Esto se puede usar como entrada a la fecha (1) para formatear la marca de tiempo según sea necesario. vea la respuesta de jgoldschrafe arriba para un ejemplo.
cas
@CraigSanders Lo bueno es que este script funciona en sistemas operativos distintos de Linux, que tienen una statutilidad diferente o ninguna.
Gilles 'SO- deja de ser malvado'
Tenga en cuenta que analizar la salida de lsno es confiable . En algunas variantes de Unix, los nombres de usuarios y grupos pueden contener espacios, lo que alterará la alineación de las columnas de fecha.
Gilles 'SO- deja de ser malvado'
@giles: cierto, pero cualquier persona sensata :-) instalaría GNU coreutils (y todas las demás herramientas de GNU) en cualquier sistema que no sea Linux. Es la forma más fácil de obtener no solo un buen conjunto de herramientas de usuario, sino también un conjunto consistente independientemente del núcleo subyacente.
cas
1
(Continuación) ... (5) Otro error: se supone que cualquier fecha / hora mostrada ls como una fecha y una hora (en lugar de una fecha y un año) debe estar en el año actual. Esto no es verdad. Es en los últimos seis meses; eso podría ser en el año anterior (por ejemplo, del 27 de septiembre de 2016 al 31 de diciembre de 2016 en los últimos seis meses). (6) A riesgo de repetir el Wiki de Greg (que @Gilles ya citó), los nombres de archivo que contienen líneas y espacios nuevos pueden hacer que esto falle. ... (Continúa)
G-Man dice 'Reincorporar a Monica' el
0

Aquí hay una versión de la línea única de cas (basada en el revestimiento de línea de goldschrafe) extendida con idempotencia ,

es decir, extendido a archivos de prefijo con fecha y hora y para hacer esto solo para aquellos que aún no tienen 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 tienen uno.

for f in * ; do
  if [[ "$f" != ????-??-??' '??:??:??' - '* ]]; then
    mv -v -- "$f" "$(date -r "$f" +%Y-%m-%d' '%H:%M:%S) - $f" ;
  fi;
done
Grzegorz Wierzowiecki
fuente
Si las marcas de tiempo de sus archivos están atornilladas y son jpegs, es posible que desee solucionarlos con datos EXIF: for f in *.jpg ; do jhead -ft "$f" ; donefuente: unix.stackexchange.com/a/290755/9689
Grzegorz Wierzowiecki