
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.jpg
wobei 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 e
nach 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 JPG
um *.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-MM
dass meine Bilder basierend auf ihren Zeitstempeln in die entsprechenden Verzeichnisse gelangen. Ich beginne also mit ls -l *.jpg > tmp.txt
dem Bildordner und füge ihn dann tmp.txt
in 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.