
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.jpg
y 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 e
despué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/month
estructura 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 JPG
para 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-MM
directorios, según sus marcas de tiempo. Entonces, lo que hago es comenzar por ls -l *.jpg > tmp.txt
la carpeta de imágenes y luego introducirla tmp.txt
en 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.