Move um grande número de arquivos para a ordem de diretório estruturado da data

5

Eu tenho cerca de 1 milhão de arquivos neste diretório: /home/username/images/

Cada um dos arquivos é chamado algo como: 012345678910(Place)_0_20120414185957_28841.jpg com a parte do registro 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 essa estrutura de data: /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?

    
por PadraigD 17.04.2012 / 12:30

4 respostas

5

Tente executá-lo na sessão de tela. Ou até mesmo tente outra construção. Eu acredito que o find + sed funcionará melhor que o bash:

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////" \&\& mv "&" "/home/username/sorted/////"%'

Isto é apenas para mostrar, como sed fazer comandos para executar. Adicionar e após o ú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////" \&\& mv "&" "/home/username/sorted/////"%e'

ps. Você não precisa usar no bash

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

O Bash pode fazer isso sozinho sem echo | cut :

day=${fullyear:6:2}
    
por 17.04.2012 / 14:36
1

Estou usando este script de shell na raiz de um diretório repleto de arquivos para movê-los todos para uma estrutura year/month -like:

#!/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.

    
por 19.01.2016 / 20:48
0

Também estou classificando imagens em diretórios estruturados por datas, mas tenho uma abordagem um pouco diferente. Eu quero minhas imagens para ir para seus respectivos diretórios YYYY-MM , com base em seus timestamps. Então, o que eu faço é que eu começo por ls -l *.jpg > tmp.txt a pasta de imagens, então eu alimentei esse tmp.txt em um loop para obter o timestamp para cada arquivo. Eu não encontrei uma maneira de obter o timestamp 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 o fizesse, esse código levaria algum tempo para ser executado. Mas funciona como pretendido.

    
por 21.06.2014 / 12:27
0

O seguinte one-liner criará um shell script 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

Eu excluí os arquivos .DS * (-não-nome ".DS *") Antes de executar o move.sh, você pode editá-lo para remover os arquivos indesejados.

    
por 05.01.2016 / 11:14