
Tenho cerca de 1 milhão de arquivos neste diretório:/home/username/images/
Cada um dos arquivos é chamado de algo como: 012345678910(Place)_0_20120414185957_28841.jpg
com a parte do carimbo de data e hora do nome do arquivo mudando em cada imagem.
O código abaixo contém código para classificar/mover os arquivos para esta estrutura de datas:/home/username/sorted/2012/04/14/18/name_of_file.jpg
Para uma pequena amostra de arquivos funciona bem, mas para o diretório enorme, meu terminal putty é desconectado após a saída
Directory $newdir does not exist. Creating same.
Eu tinha outro código que sempre morria com o código de erro argument list too long
.
Aqui está o 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
Alguma idéia de por que a conexão não será mantida durante a execução do loop grande?
Responder1
Tente executá-lo na sessão de tela. Ou até tente outra construção. Acredito que find + sed funcionará melhor que o 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/"%'
Isso é apenas para mostrar como os comandos sed make devem ser executados. Adicionar e
depois do último %
forçará a execução do 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'
obs. Você não precisa usar no bash
day=$(echo $fullyear |cut -c7-8)
Bash pode fazer isso sozinho sem echo | cut
:
day=${fullyear:6:2}
Responder2
Estou usando este script de shell na raiz de um diretório repleto de arquivos para movê-los todos para uma year/month
estrutura semelhante 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 para a estrutura correta.
Responder3
Também estou classificando imagens em diretórios estruturados por data, mas tenho uma abordagem um pouco diferente. Quero que minhas imagens vão para seus respectivos YYYY-MM
diretórios, com base em seus carimbos de data/hora. Então, o que faço é começar pela ls -l *.jpg > tmp.txt
pasta de imagens e, em seguida, alimentar isso tmp.txt
em um loop para obter o carimbo de data e hora de cada arquivo. Não encontrei uma maneira de obter o carimbo de data / hora de outra forma.
Aqui está o meu 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
Não tenho milhões de imagens para classificar e, se tivesse, esse código levaria algum tempo para ser executado. Mas funciona como pretendido.
Responder4
A linha a seguir criará um script de shell para mover os arquivos para a pasta correta com base na hora modificada.
find . -type f -not -name ".DS*" -exec stat -f "mkdir -p %Sm; mv \"%N\" %Sm" -t "%Y/%m/%d" {} \; > move.sh
sh move.sh
Excluí arquivos .DS* (-not -name ".DS*") Antes de executar o move.sh, você pode editá-lo para remover os arquivos indesejados.