ubuntuusers.de

Bash-Script zum Sortieren von Bildern anhand Dateinamen - Kein Exif!

Status: Ungelöst | Ubuntu-Version: Server 23.04 (Lunar Lobster)
Antworten |

TrashCo92

Anmeldungsdatum:
3. Dezember 2023

Beiträge: 2

Nabend zusammen,

ich bin schon länger auf der Suche nach einem Script zum automatisierten Sortieren der Bilder unter Linux. Meine Versuche mit Exif-Tool sind gescheitert da einige Bilder keine Exif-Daten enthalten.

Ich habe Jahrelang unter Windows Server ein Bash-Script gehabt dass anhand des Dateinahmen sich das Datum rausgepickt hat, entsprechende Ordner erstellt, und die Dateien darin verschoben hat im Format YYYY/MM/:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
@echo off & setlocal

:Sortierung

    set "QUELLE=E:\Melina\Bilder\Sync"
    set "Ziel=E:\Melina\Bilder"

    if "%~1" neq "" pushd %1
    for %%i in ("%QUELLE%\*.*") do (
    for /f "tokens=1-3 delims=. " %%a in ("%%~ti") do (
        if not exist "%Ziel%\%%c\%%b" md "%Ziel%\%%c\%%b"
        move %%i "%Ziel%\%%c\%%b\"
    )
    )
    if "%~1" neq "" popd

goto ende

:ende

Die Bilder enthalten immer solche Namen in etwa: IMG-YYYYMMDD-XXXXX.jpg oder IMG_YYYYMMDD_XXXXXX.jpg

Ich denke dass es unter Linux mindestens genauso leicht geht wie unter Windows. Leider bin ich in dieser Hinsicht mit Linux noch sehr grün hinter den Ohren und tue mich unheimlich schwer gerade... ☹

Grüße TrashCo92

shiro Team-Icon

Supporter

Anmeldungsdatum:
20. Juli 2020

Beiträge: 1274

Probier mal

QUELLE=$HOME/Bilder/Sync
ZIEL=$HOME/Bilder
for i in "$QUELLE/"*.jpg; do d="$ZIEL/$(sed 's#^[^12]*\(....\)\(..\).*$#\1/\2#' <<<$i)";[ -d "$d" ] || echo mkdir -p "$d"; echo cp $i "$d"; done

Kommentar:

  • Beim "for" kannst du statt "*.jpg" die Bildnamen auch eingrenzen z.B. mit "IMG[0-9-_]*.jpg".

  • Bei dem "sed" Befehl werden am Anfang alle Zeichen ignoriert, die nicht mit "1" oder "2" beginnen (bis zum Jahr 19xx und 2xxx).

  • Dann werden 4 Zeichen in dem Zwischenspeicher 1 und die folgenden 2 Zeichen in dem Zwischenspeicher 2 gemerkt. Bei der Ausgabe werden die beiden Speicher-Werte durch "/" getrennt (\1/\2).

  • Wenn das Zielverzeichnis "d" des Bildes nicht existiert ([-d $d] ||) wird das Verzeichnis erstellt (mkdir -p).

  • Dann wird die Datei "$i" in das Zielverzeichnis "$d" kopiert.

Ich habe vor den Befehlen "mkdir" und "cp" ein "echo" stehen. Dies bewirkt, dass die Befehle nur ausgegeben und nicht umgesetzt werden. Wenn das Ergebnis deinen Vorstellungen entspricht, löscht du die beiden "echo" Befehle einfach. Statt des "cp" zum kopieren kannst duch auch "mv" (move) verwenden.

steamywindows

Avatar von steamywindows

Anmeldungsdatum:
5. Mai 2018

Beiträge: 31

Mist, zu langsam gewesen 😀

Ich habe ein kleines Skript zusammengeschrieben, das hier helfen könnte:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#!/bin/bash

QUELLE="/PFAD_zu_Ordner/Melina/Bilder/Sync/"
ZIEL="/PFAD_zu_Ordner/Melina/Bilder/"

if [ ! -d ${QUELLE} ];then echo "Verzeichnis ${QUELLE} nicht vorhanden!"; exit 1;fi

# Liste aller jpg-Dateien in Quelle erstellen und sortieren:
for image in $(find $QUELLE -name "*jpg" | sort -h)
do
	# festellen, ob es 2 Unterstriche im Dateinamen gibt, sonst 2 Bindestriche voraussetzen:
	if [ $(awk -F"_" '{print NF-1}' <<< "${image}") -eq 2 ]
	then
		dateidatum=$(echo "${image}" | cut -f2 -d '_' | cut -f1 -d '_')
	else
		dateidatum=$(echo "${image}" | cut -f2 -d '-' | cut -f1 -d '-')
	fi
	# Zielorder mit Ziel, Jahr und Monat zusammensetzen:
	ordner="${dateidatum:0:4}/${dateidatum:4:2}/"
	# Sicherstellen, dass es Zielordner gibt, sonst anlegen:
	test -d "${ordner}" || mkdir -p "${ordner}"
	# Dateien kopieren (ggf. mit mv austauschen zum Verschieben):
	cp "${image}" "${ordner}"
	# Debug-Output:
	#echo -e "image ${image} mit dateidatum ${dateidatum} wird kopiert in zielordner ${ZIEL}${ordner}"
done

exit 0

TrashCo92

(Themenstarter)

Anmeldungsdatum:
3. Dezember 2023

Beiträge: 2

Hallo Zusammen,

Danke erstmal an Euch für die Hilfestellung 😀

Ich werd mal beide Scripte die Tage ausprobieren, und mich bissl einlesen um Sie auch zu verstehen wie Sie funktionieren damit der Lerneffekt auch nicht ausbleibt 😉 was mir auffällt, dass beide Scripte total andere Ansätze verfolgen, da scheint Linux mehrere Wege zu bieten, aber letztendlich führen bekanntlich alle Wege nach Rom 😊

Ich melde mich dann nochmal ob alles geklappt hat oder Rückfragen da sind! 👍

shiro Team-Icon

Supporter

Anmeldungsdatum:
20. Juli 2020

Beiträge: 1274

... da scheint Linux mehrere Wege zu bieten ...

Das ist richtig, aber im Prinzip unterscheiden sich die beiden Varianten nicht sonderlich. Beide setzten auf dem im Dateinamen hinterlegten Datum auf.

In deinem "cmd" Script wird allerdings per '("%%~ti")' auf den Timestamp der Datei aufgesetzt. Dies ist insofern problematisch, weil beim kopieren einer Datei ein neuer "Creation-Timestamp" angelegt wird, wenn man nicht grade per "cp -p" die Bilder von der Kamera kopieren konnte.

Der im Dateinamen durch die Kamera hinterlegte Aufnahmezeitpunkt verändert sich nicht (wie auch die exif Daten, wenn man sie nicht ändert). Insofern ist der Ansatz, über den Dateinamen das Verzeichnis (Jahr/Monat) zu ermitteln sicherer. Wenn du aber bei dem Windows Beispiel auf das Erstellungsdatum der Datei abheben willst, geht das auch (z.B. über "stat -c '%w' file"). Das Zuordnen der einzelnen "for /f" Tokens (a,b,c..) geht so ähnlich in der Bash. Hier werden allerdings nicht aufeinanderfolgende Variablen verwendet sondern ein Array, dass man indiziert ansteuern kann. Beispiel:

$ stat -c %w IMG-20231104-123456.jpg 
2023-12-04 15:46:38.449592798 +0100
$ arr=( $(stat -c "%w" IMG-20231104-123456.jpg | tr '-' ' ') )
$ echo "Jahr=${arr[0]}, Monat=${arr[1]}"
Jahr=2023, Monat=12

Marc_BlackJack_Rintsch Team-Icon

Ehemalige
Avatar von Marc_BlackJack_Rintsch

Anmeldungsdatum:
16. Juni 2006

Beiträge: 4687

Wohnort: Berlin

Etwas das unter Windows und Linux funktionieren sollte, in Python (natürlich ungetestet):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#!/usr/bin/env python3
import re
import shutil
from pathlib import Path
#
# IMG-YYYYMMDD-XXXXX.jpg
#    ||   | |
#    12   3 4  <- regex group starts
#
DATE_RE = re.compile(r"[^_-]*(.)(\d{4})(\d{2})(\d{2})\1")

SOURCE_PATH = Path("/E/Melina/Bilder/Sync")
TARGET_PATH = Path("/E/Melina/Bilder")


def main():
    for path in SOURCE_PATH.iterdir():
        match = DATE_RE.match(path.name)
        if match:
            _delimiter, year, month, _day = match.groups()
            target_path = TARGET_PATH / year / month
            target_path.mkdir(exist_ok=True)
            shutil.move(path, target_path)


if __name__ == "__main__":
    main()

shiro Team-Icon

Supporter

Anmeldungsdatum:
20. Juli 2020

Beiträge: 1274

shiro schrieb: Es geht noch einfacher mit printf

$ stat -c %w IMG-20231104-123456.jpg 
2023-12-04 15:46:38.449592798 +0100
$ printf "%(%Y/%m)T\n" $(stat -c "%W" IMG-20231104-123456.jpg)
2023/12

Beachte die Groß-/Kleinschreibung des Parameter "%W".

Antworten |