Verschieben Sie eine große Anzahl von Dateien in eine datumsstrukturierte Verzeichnisreihenfolge

Verschieben Sie eine große Anzahl von Dateien in eine datumsstrukturierte Verzeichnisreihenfolge

Ich habe ungefähr 1 Million Dateien in diesem Verzeichnis:/home/username/images/

Der Name der einzelnen Dateien lautet ungefähr: 012345678910(Place)_0_20120414185957_28841.jpgwobei sich der Zeitstempelteil des Dateinamens bei jedem Bild ändert.

Der folgende Code enthält Code zum Sortieren/Verschieben der Dateien in diese Datumsstruktur:/home/username/sorted/2012/04/14/18/name_of_file.jpg

Für eine kleine Auswahl von Dateien funktioniert es gut, aber für das riesige Verzeichnis wird mein Putty-Terminal nach der Ausgabe getrennt

Directory $newdir does not exist.  Creating same.

Ich hatte anderen Code, der immer mit dem Fehlercode abbrach argument list too long.

Hier ist der Code:

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

Irgendwelche Ideen, warum die Verbindung beim Ausführen der großen Schleife nicht gehalten wird?

Antwort1

Versuchen Sie, es in einer Bildschirmsitzung auszuführen. Oder versuchen Sie sogar eine andere Konstruktion. Ich glaube, find + sed funktioniert besser als reines 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/\1/\2/\3/\4" \&\& mv "&" "/home/username/sorted/\1/\2/\3/\4/"%'

Dies dient nur zur Veranschaulichung, wie sed Befehle ausführt. Das Hinzufügen enach last %erzwingt die Ausführung des Befehls:

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'

ps. Sie müssen nicht in Bash verwenden

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

Bash kann dies selbst tun, ohne echo | cut:

day=${fullyear:6:2}

Antwort2

Ich verwende dieses Shell-Skript im Stammverzeichnis eines mit Dateien vollgepackten Verzeichnisses, um sie alle in eine year/month-ähnliche Struktur zu verschieben:

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

Verwendung: $ ./pictures.sh JPGum *.JPG in die richtige Struktur zu bringen.

Antwort3

Ich sortiere Bilder auch in datumsstrukturierte Verzeichnisse, habe aber einen etwas anderen Ansatz. Ich möchte, YYYY-MMdass meine Bilder basierend auf ihren Zeitstempeln in die entsprechenden Verzeichnisse gelangen. Ich beginne also mit ls -l *.jpg > tmp.txtdem Bildordner und füge ihn dann tmp.txtin eine Schleife ein, um den Zeitstempel für jede Datei zu erhalten. Ich habe keinen anderen Weg gefunden, den Zeitstempel zu erhalten.

Hier ist mein Code:

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

Ich muss nicht Millionen von Bildern sortieren und wenn ich welche hätte, würde die Ausführung dieses Codes ziemlich lange dauern. Aber er funktioniert wie vorgesehen.

Antwort4

Der folgende Einzeiler erstellt ein Shell-Skript, um die Dateien basierend auf der Änderungszeit in den richtigen Ordner zu verschieben.

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

Ich habe .DS*-Dateien ausgeschlossen (-nicht -name ".DS*"). Bevor Sie move.sh ausführen, können Sie es bearbeiten, um die unerwünschten Dateien zu entfernen.

verwandte Informationen