Dateien aufgrund von Variablen umbenennen, verschieben und löschen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
novregen
User
Beiträge: 15
Registriert: Montag 14. Januar 2019, 11:49

Hallo,

ich würde gerne mit einem Pyhton Script folgende Aufgabe erledigen lassen:

In einem Scan Ordner sind laufen folgende Dateitypen rein:
ReA_BestellungTest.pdf
ReT_Mai.pdf
No_Test.txt

Ich wüde dort jetzt gerne ein Script laufen lassen, welches der Datei ein Datum yyyy_mm_tt voraussetzt und dann aufgrund der Variablen ReA / ReT / No ausschreibt 2019_01_14_Rechnung Telekom_hier den Orignal Text behält der hinter _kommt ggfs. bei doppeltem Namen hier ein _1
Die neu benannte Datei sollte dann in ein anderes Verzeichnis geschrieben werden, und die Ursprungsdatei gelöscht werden.

Ich habe schon mal versucht, komme aber jetzt nicht weiter, vielleicht kann mir ja jemand helfen, ich suche hier nur ein Script, weil es ein fertiges Programm für die NAS leider nicht gibt....

import os
import datetime

src = '/volume1/homes/XX/test.pdf'
dst = '/volume1/homes/XY/%s-text.pdf' % datetime.datetime.now()
os.rename(src, dst)
Benutzeravatar
sparrow
User
Beiträge: 4164
Registriert: Freitag 17. April 2009, 10:28

Grundsätzlich kannst du mit der Funktion copy aus dem Modul shutil Dateien kopieren und bei der Gelegenheit auch umbenennen.

Eine fertige Lösung wird dir hier aber wahrscheinlich niemand liefern.

Dein Ansinnen ist für einen Anfänger aber nicht wenig komplex.
Grundsätzlich musst du über eine Dateiliste iterieren und die Dateinamen interpretieren.
NPC
User
Beiträge: 54
Registriert: Dienstag 8. Januar 2019, 17:51

Hallo,

Zum auslesen des Datums greifst du auf die Metadaten zu. Hierfür kannst du

Code: Alles auswählen

os.stat(<path>)
verwenden.
Mittels

Code: Alles auswählen

os.listdir(<path>)
kannst du alle Dateien in einem Ordner auflisten lassen.
Du bekommst eine Liste zurück.

Hoffe das hilft dir :)
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

@novregen: an welcher Stelle kommst Du nicht weiter? Mit os.listdir kann man Dateien auflisten, mit startswith kann man die verschiedenen Typen unterscheiden. Und os.rename kennst Du schon.
novregen
User
Beiträge: 15
Registriert: Montag 14. Januar 2019, 11:49

Sirius3 hat geschrieben: Montag 14. Januar 2019, 13:14 @novregen: an welcher Stelle kommst Du nicht weiter? Mit os.listdir kann man Dateien auflisten, mit startswith kann man die verschiedenen Typen unterscheiden. Und os.rename kennst Du schon.
Hallo Sirius,
also ich kann mit dem nachfolgenden Script umbenennen, in anderen ordner verschieben und er löscht auch. Anscheinend alles mit os.rename.
Wo ich nicht weiterkomme ist:
- ich schaffe es nicht das er Teile des Namens nimmt also ReA*
- ich schaffe es nicht das ich alles was hinter ReA_ kommt in den neuen Dateinamen zu übernehmen
- ich möchte noch mehrere Variablen aufnehmen, also zu ReA auch ReT

import os
import datetime

src = '/volume1/xx/ReA_1.pdf'
dst = '/volume1/xx/DMS/%s-text.pdf' % datetime.date.today()
os.rename(src, ds
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Schau dir mal das Modul "glob" an, und/oder fnmatch (nur das string-matching).
novregen
User
Beiträge: 15
Registriert: Montag 14. Januar 2019, 11:49

Ohne eine Variabel funktioniert es (erster Teil), beim zweiten Teil, wo ich versucht habe glob zu verwenden bekomme ich eine Fehlermeldung.

import os
import datetime
import glob

src = '/volume1/xx/ReT.pdf'
dst = '/volume1/xx/DMS/%s_RG-Telekom.pdf' % datetime.date.today()
os.rename(src, dst)

for f in glob.glob('/volume/xx/ReA*.pdf'):
new_filename = '/volume1/xx/DMS/%s_RG-Amazon.pdf' % datetime.date.today()
os.rename(f,new_filename)


File "/volume1/xx/UmbenennenA.py", line 10
new_filename = '/volume1/xx/DMS/%s_RG-Amazon.pdf' % datetime.date.today()
^
IndentationError: expected an indented block
Benutzeravatar
sparrow
User
Beiträge: 4164
Registriert: Freitag 17. April 2009, 10:28

Bitte setze deinen Code hier im Forum in Code-Tags (das ist der </>-Knopf über dem Eingabefeld), damit die Einrückung erhalten bleibt.

Einrückung ist in Python wichtig, weil so Blöcke gebildet werden. Die Fehlermeldung deutet darauf hin, dass das hier nicht gemacht wurde. Und das deutet darauf hin, dass du dich mit dem Python-Tutorial beschäftigen möchtest.
novregen
User
Beiträge: 15
Registriert: Montag 14. Januar 2019, 11:49

Ich habe das in Sublime Text getippt bzw. kopiert

Code: Alles auswählen


import os
import datetime
import glob

src = '/volume1/xx/ReT.pdf'
dst = '/volume1/xx/DMS/%s_RG-Telekom.pdf' % datetime.date.today()
os.rename(src, dst)

for f in glob.glob('/volume1/xx/ReA*.pdf'):
	new_filename = '/volume1/xx/DMS/%s_RG-Amazon.pdf' % datetime.date.today()
	os.rename(f,new_filename)

Benutzeravatar
__blackjack__
User
Beiträge: 13003
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@novregen: Das sieht jetzt soweit okay aus, aber da werden Tabulatorzeichen verwendet. Konvention sind vier Leerzeichen pro Ebene. Und auf keinen Fall Tabs und Leerzeichen mischen, denn dann kann genau so etwas passieren, dass der Code zwar korrekt eingerückt *aussieht* aber es nicht ist. Deswegen die Konvention von vier Leerzeichen und keine Tabs.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
novregen
User
Beiträge: 15
Registriert: Montag 14. Januar 2019, 11:49

also muss ich den Bereich vor new_filename und os.rename prüfen bzw. dort alles raus und 4 Leerzeichen davor ?
Benutzeravatar
__blackjack__
User
Beiträge: 13003
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@novregen: Ja, allerdings kann das nicht das Problem sein, denn zumindest hier im Forum scheinen beide Zeilen mit genau einem Tab zu beginnen.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
novregen
User
Beiträge: 15
Registriert: Montag 14. Januar 2019, 11:49

Es war dort an der Stelle auch ein normaler Tab, ich habe nochmal alles per Hand in Subline eingegeben, jetzt funktioniert es.

Jetzt ist noch die Frage:
- kann ich die Verschiedenen Möglichkeiten noch anders darstellen als unten aufgeführt
- wie bekomme ich es hin, das er den Ursprungstext mit in den neuen Dateinamen aufnimmt
Ursprung ReA_Instar Kamera 9008 -> Neu 2019-01-15_RG-Amazon_Instar Kamera 9008
Datum und RG-Amazon funktioniert ja schon nur den Ursprungstext mit übernehmen habe ich noch nicht raus
-wenn trotz Ursprungstext doppelt oder Datei schon vorhanden, kann ich _1 setzten lassen ?

Code: Alles auswählen

import os
import datetime
import glob

for f in glob.glob('/volume1/xx/ReA*.pdf'):
    new_filename = '/volume1/xx/DMS/%s_RG-Amazon.pdf' % datetime.date.today()
    os.rename(f,new_filename)

for f in glob.glob('/volume1/xx/GsA*.pdf'):
    new_filename = '/volume1/xx/DMS/%s_GS-Amazon.pdf' % datetime.date.today()
    os.rename(f,new_filename)

for f in glob.glob('/volume1/xx/ReT*.pdf'):
    new_filename = '/volume1/xx/DMS/%s_RG-Telekom.pdf' % datetime.date.today()
    os.rename(f,new_filename)

for f in glob.glob('/volume1/xx/NoE*.pdf'):
    new_filename = '/volume1/TD/DMS/%s_Notiz-EDV.pdf' % datetime.date.today()
    os.rename(f,new_filename)
Benutzeravatar
__blackjack__
User
Beiträge: 13003
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@novregen: Ich würde hier ja mit dem `glob()` generell alle ``*.pdf`` erfassen und den konkreten ”Typ” dann manuell prüfen. Dann hat man nur eine Schleife, muss nur einmal durch das Verzeichnis gehen, und hat den Code der ja im Grunde immer das gleiche macht nur einmal.

Die Zuordnungen von Anfang der Zeichenkette zu Langfassung sollte in einer passenden Datenstruktur stehen. Beispielsweise in einer Liste mit Tupeln oder einem Wörterbuch. Dann kann man die mit einer Schleife abarbeiten und leicht erweitern und ändern.

Wobei mir da gerade eine Unregelmässigkeit auffällt: In der letzten Schleife ist der Teil des neuen Pfades der in allen anderen …/xx/… heisst plötzlich …/TD/… – soll das so? Wenn nein, dann ist das einer der Gründe warum man keinen Code kopiert und ein bisschen ändert, sondern die Unterschiede aus solchen Code-Stücken heraus zieht und eine Funktion schreibt und/oder eine Schleife über die Unterschiede verwendet.

Auch Teilinformationen sollte man nicht mehrfach im Quelltext stehen haben. Wenn sich da mal etwas ändert, muss man alle Kopien ändern was immer die Gefahr birgt, das man es geringfügig anders macht oder welche vergisst und sich so Fehler einbaut. Mehrfach verwendete (Teil)Pfade würde man als Konstante definieren.

Statt ``%`` würde man in neuem Code eher die `format()`-Methode verwenden. In aktuellen Python 3-Versionen eventuell auch f-Zeichenketten.

Das Datum würde ich nur einmal am Anfang ermitteln. Das ändert sich ja sehr unwahrscheinlich während das Skript läuft, und wenn, dann ist die Frage ob das tatsächlich schlimm ist wenn man kurz nach Mitternacht noch das Datum verwendet an dem die Umbenennung gestartet wurde.

`f` ist kein guter Name. Wie fast alle einbuchstabigen Namen.

Wenn Du einen Teil des ursprünglichen Namens verwenden willst, musst Du den entsprechend zerlegen und das isolieren was Du für den Zielnamen brauchst. Für Pfade und Dateinamen hat das `os.path()`-Modul viele Funktionen. Die sollte man direkten Zeichenkettenmanipulationen vorziehen. Wobei ich an der Stelle auch `glob()` in Frage stellen würde. Zumindest wenn man den Anfang der Dateinamen manuell prüfen muss. Denn dafür muss man den Pfad vom Dateinamen trennen, was bei `os.listdir()` ja schon von Haus aus so ist, weil man da nur den Dateinamen ohne den Pfad davor bekommt.

Klar kann man Zahlen an den Dateinamen anhängen um Namenskollisionen zu vermeiden. Das muss man halt programmieren.

Du solltest grundsätzlich mal mit Funktionen anfangen. Das ist schon komplex genug das Du sicher einzelne Schritte auch mal separat testen möchtest. Dazu bietet es sich an das Programm so zu schreiben das der Code in Funktionen steckt und die Hauptfunktion nur läuft wenn man das als Programm ausführt, aber *nicht* wenn man es als Modul importiert. Denn dann kann man es zum Beispiel in einer Python-Shell importieren und einzelne Funktionen manuell testen. Oder auch in einem anderen Modul importieren und automatisierte Tests durchführen.

Hier mal Dein Code überarbeitet, ungetestet, und unter der Annahme das alle in das gleiche Zielverzeichnis sollen:

Code: Alles auswählen

#!/usr/bin/env python3
import datetime
import glob
import os

SOURCE_PATH = '/volume1/xx'
TARGET_PATH = os.path.join(SOURCE_PATH, 'DMS')


def main():
    today = datetime.date.today()
    
    for prefix, name_part in [
        ('ReA', 'RG-Amazon'),
        ('GsA', 'GS-Amazon'),
        ('ReT', 'RG-Telekom'),
        ('NoE', 'Notiz-EDV'),
    ]:
        filenames = glob.iglob(os.path.join(SOURCE_PATH, prefix + '*.pdf'))
        for old_filename in filenames:
            new_filename = os.path.join(TARGET_PATH, f'{today}_{name_part}.pdf')
            os.rename(old_filename, new_filename)


if __name__ == '__main__':
    main()
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
novregen
User
Beiträge: 15
Registriert: Montag 14. Januar 2019, 11:49

Hallo blackjack,

vielen Dank für die Antwort. Da muss ich erstmal gucken wie sich das zusammensetzt.
Ich habe den Code einfach mal übernommen und bekomme folgende Fehlermeldung.

Ich verstehe hier nicht ganz das f' in Line 21

File "/volume1/xx/UmbenennenA4.py", line 21
new_filename = os.path.join(TARGET_PATH, f'{today}_{name_part}.pdf')
^
SyntaxError: invalid syntax

Hier der Code wie er bei mir dargestellt wird. Kannst du für einfach Anwendungen noch was anderes empfehlen als Subline ?

Code: Alles auswählen

#!/usr/bin/env python3
import datetime
import glob
import os

SOURCE_PATH = '/volume1/TD'
TARGET_PATH = os.path.join(SOURCE_PATH, 'DMS')


def main():
    today = datetime.date.today()
    
    for prefix, name_part in [
        ('ReA', 'RG-Amazon'),
        ('GsA', 'GS-Amazon'),
        ('ReT', 'RG-Telekom'),
        ('NoE', 'Notiz-EDV'),
    ]:
        filenames = glob.iglob(os.path.join(SOURCE_PATH, prefix + '*.pdf'))
        for old_filename in filenames:
            new_filename = os.path.join(TARGET_PATH, f'{today}_{name_part}.pdf')
            os.rename(old_filename, new_filename)
Benutzeravatar
__blackjack__
User
Beiträge: 13003
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@novregen: Da ist das Python anscheinend zu alt für f-Zeichenketten. Dann müsste man an der Stelle die `format()`-Methode auf Zeichenketten verwenden.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
novregen
User
Beiträge: 15
Registriert: Montag 14. Januar 2019, 11:49

Hallo blackjack,

danke, aber ich wußte nicht ganz genau wie ich es machen musste. Mit format() hat es nicht geklappt. So mit .format funktioniert es zumindest so weit, das ich Dateien
2019-01-16_RG-Amazon etc. erhalten, was jedoch noch nicht funktioniert ist, das der Teil des alten Namen mit übernommen wird. Also z.B. Ursprung "ReA_Instar Kamera"
neu dann 2019-01-16_RG-Amazon_Instar Kamera

Code: Alles auswählen

filenames = glob.iglob(os.path.join(SOURCE_PATH, prefix + '*.pdf'))
        for old_filename in filenames:
            new_filename = os.path.join(TARGET_PATH, '{}_{}.pdf'.format(today, name_part))
            os.rename(old_filename, new_filename)
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

@novregen: dann schau Dir in der Dokumentation noch einmal an, wie man format benutzt.
novregen
User
Beiträge: 15
Registriert: Montag 14. Januar 2019, 11:49

Tut mir leid, ich komme irgendwie nicht darauf, wo dieser Teil des Names separiert wird, und wie er definiert ist, das ich ihn dort verwenden könnte.
Benutzeravatar
__blackjack__
User
Beiträge: 13003
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@novregen: Der Teil des Namens wird nicht separiert, ist also nirgends definiert. Das musst Du halt machen, also Code dafür schreiben. Du hast ja den Präfix der weg soll und den gesamten Pfad als Ausgangsdaten. Davon brauchst Du den Dateinamen, und von dem dann nur den Teil nach dem Präfix. Für's erste gibt es eine Funktion in `os.path`, und das zweite sind Grundoperationen bei Zeichenketten die im Tutorial in der Python-Dokumentation vorkommen. Die Länge des Teils ermitteln der nicht im Ergebnis sein soll und dann die entsprechende Teilzeichenkette erstellen.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Antworten