Mueva una gran cantidad de archivos al orden de directorio estructurado por fecha

Mueva una gran cantidad de archivos al orden de directorio estructurado por fecha

Tengo alrededor de 1 millón de archivos en este directorio:/home/username/images/

Cada uno de los archivos se llama algo así como: 012345678910(Place)_0_20120414185957_28841.jpgy la parte de la marca de tiempo del nombre del archivo cambia en cada imagen.

El siguiente código contiene código para ordenar/mover los archivos a esta estructura de fechas:/home/username/sorted/2012/04/14/18/name_of_file.jpg

Para una pequeña muestra de archivos, funciona bien, pero para el directorio enorme, mi terminal PuTTY se desconecta después de generar

Directory $newdir does not exist.  Creating same.

Tenía otro código que siempre moría con el código de error argument list too long.

Aquí está el código:

#!/bin/bash
ALLFILES=(images/*)
for ((i=0; i<${#ALLFILES[*]}; i+=30000));
do
    set $(echo "${ALLFILES[@]:i:30000}" | awk -F_ '{print $1, $2, $3, $4, $5}')
    fullyear=$3
    year=$(echo $fullyear |cut -c1-4)
    month=$(echo $fullyear |cut -c5-6)
    day=$(echo $fullyear |cut -c7-8)
    hour=$(echo $fullyear |cut -c9-10)
    newdir=$(echo /home/username/sorted/$year/$month/$day/$hour/)
    if ! [ -d $newdir ]; then
        echo Directory $newdir does not exist.  Creating same.
        mkdir -p $newdir;
    fi
    mv "${ALLFILES[@]:i:30000}" $newdir;
done

¿Alguna idea de por qué la conexión no se mantendrá mientras se realiza el bucle grande?

Respuesta1

Intente ejecutarlo en la sesión de pantalla. O incluso probar con otra construcción. Creo que find + sed funcionará mejor que bash puro:

find images/ -name "*.jpg" | sed 's%^[^_]*_[^_]*_\([0-9][0-9][0-9][0-9]\)\([0-9][0-9]\)\([0-9][0-9]\)\([0-9][0-9]\).*%mkdir -p "/home/username/sorted/\1/\2/\3/\4" \&\& mv "&" "/home/username/sorted/\1/\2/\3/\4/"%'

Esto es solo para mostrar cómo sed crea comandos para ejecutar. Agregar edespués del último %forzará la ejecución del comando:

find images/ -name "*.jpg" | sed 's%^[^_]*_[^_]*_\([0-9][0-9][0-9][0-9]\)\([0-9][0-9]\)\([0-9][0-9]\)\([0-9][0-9]\).*%mkdir -p "/home/username/sorted/\1/\2/\3/\4" \&\& mv "&" "/home/username/sorted/\1/\2/\3/\4/"%e'

PD. No necesitas usarlo en bash

day=$(echo $fullyear |cut -c7-8)

Bash puede hacerlo solo sin echo | cut:

day=${fullyear:6:2}

Respuesta2

Estoy usando este script de shell en la raíz de un directorio repleto de archivos para moverlos todos a una year/monthestructura similar a:

#!/usr/bin/env bash

if [ ! $1 ]; then
    echo "Usage: ./pictures.sh jpg"
    exit 1
fi

for f in *."$1"; do
    FILENAME="$f"
    YEAR=`date -j -f "%s" $(stat -f "%m" "$FILENAME") +"%Y"`
    MONTH=`date -j -f "%s" $(stat -f "%m" "$FILENAME") +"%m_%B"`
    DEST="$YEAR/$MONTH"

    if [ ! -d "$DEST" ]; then
        mkdir -p "$DEST"
    fi

    echo "Moving $FILENAME to $DEST/$FILENAME ..."
    mv "$FILENAME" "$DEST/$FILENAME"
done

Uso: $ ./pictures.sh JPGpara mover *.JPG a la estructura correcta.

Respuesta3

También estoy ordenando imágenes en directorios estructurados por fechas, pero tengo un enfoque ligeramente diferente. Quiero que mis imágenes vayan a sus respectivos YYYY-MMdirectorios, según sus marcas de tiempo. Entonces, lo que hago es comenzar por ls -l *.jpg > tmp.txtla carpeta de imágenes y luego introducirla tmp.txten un bucle para obtener la marca de tiempo de cada archivo. De lo contrario, no he encontrado una manera de obtener la marca de tiempo.

Aquí está mi código:

#!/bin/bash
hostdir="/home/Photos/"
destdir="/tmp/sorted"

cd $hostdir

touch /tmp/tmpsort.txt
ls -l *.jpg > /tmp/tmpsort.txt

while read line
do
    filename=$(echo $line | awk '{print $8}')
    filedate=$(echo $line | awk '{print $6}')
    filedir=${filedate:0:7}

    if [ ! -d $destdir/$filedir ]; then
        mkdir -p $destdir/$filedir
    fi

    # Let's skip files that were already sorted from a previous run
    if [ ! -f $destdir/$filedir/$fiename ]; then
        cp $filename $destdir/$filedir/
    fi

done < /tmp/tmpsort.txt
rm /tmp/tmpsort.txt

No tengo millones de imágenes para ordenar y, si las tuviera, este código tardaría bastante en ejecutarse. Pero funciona según lo previsto.

Respuesta4

La siguiente línea creará un script de shell para mover los archivos a la carpeta correcta según la hora de modificación.

find . -type f -not -name ".DS*" -exec stat -f "mkdir -p %Sm; mv \"%N\" %Sm" -t "%Y/%m/%d" {} \; > move.sh
sh move.sh

He excluido los archivos .DS* (-not -name ".DS*") Antes de ejecutar move.sh, puede editarlo para eliminar los archivos no deseados.

información relacionada