Seite 1 von 3

Python Script zum ändern von Dateiendungen

Verfasst: Donnerstag 5. Januar 2012, 12:52
von korkak
hi zusammen,

endlich hab ichs geschafft, mein erstes selbst gebautes python script :D
und es funktioniert auch so wie ich es mir vorstelle, ich würde nur gern wissen ob ihr das so ok findet oder ob ihr verbesserungsvorschläge habt, ich will ja was lernen :)


import os, glob, string
p = raw_input("Bitte den vollständigen Pfad eingeben: ")
if os.path.exists(p):
e = raw_input("Welche Dateiendung, z.B.: .txt, soll geändert werden? ")
n = raw_input("Wie lautet die neue Dateiendung, z.B.: .jpg? ")
print(p, " : Pfad existiert!")
os.chdir(p)
filenames = glob.glob('*' + e)
print("Folgende Dateien wurden gefunden:")
for file in filenames:
print(file)
i = 0
for filename in filenames:
newfilename = string.replace(filename, e, n)
os.rename(filename, newfilename)
i = i + 1
print(i, "Dateien wurden umbenannt.")
else:
print(p, " : Pfad existiert nicht!")

gruß
korkak

ps: irgendwie übernimmt der die formatierung von den einrückungen nicht...

Re: Python Script zum ändern von Dateiendungen

Verfasst: Donnerstag 5. Januar 2012, 13:23
von nomnom
ps: irgendwie übernimmt der die formatierung von den einrückungen nicht...
Das liegt daran, dass du deinen Code ausdrücklich in python-Tags schreiben musst.
  • `os.chdir(p)` ganz böse! ;-) Man erwartet von einem Skript nicht, dass es einfach das Verzeichnis wechselt, wenn man es aufruft.
  • Du kannst dir auch mal `os.walk` anschauen.
  • `string.replace(filename, e, n)` Da ist ein logischer Fehler drin. Da wird nicht nur die Dateiendung geändert … Außerdem solltest du lieber filename.replace(e, n) benutzen. Und wenn du eine Variable sowieso nur einmal verwendest, kannst du den Wert gleich der benutzenden Funktion übergeben.
  • Bei Python 2 ist `print` keine Funktion, sondern ein Statement! Du solltest `print` auch so behandeln, denn das sieht komisch aus:

    Code: Alles auswählen

    >>> print('foo', 'bar')
    ('foo', 'bar')
    >>> 

Re: Python Script zum ändern von Dateiendungen

Verfasst: Donnerstag 5. Januar 2012, 13:41
von sma
Ich würde es vielleicht so machen:

Code: Alles auswählen

import glob, os, sys

verbose = "-v" in sys.argv[:1]
if verbose:
    del sys.argv[0]

try:
    path, old_ext, new_ext = sys.argv
except ValueError:
    print "usage: rename [-v] <path> <old_ext> <new_ext>"
    sys.exit(1)

if not os.path.exists(path):
    print "rename: %s doesn't exist" % path
    sys.exit(1)

names = glob.glob(os.path.join(path, "*" + old_ext))

for name in names:
    new_name = name.replace(old_ext, new_ext)
    os.rename(name, new_name)
    if verbose:
        print "rename: %s -> %s" % (name, new_name)

if verbose:
    print "rename: %d files renamed" % len(names)
Bei einem Script erwarte ich nicht, dass es mich nach Informationen fragt, sondern dass ich Parameter per Kommandozeile übergebe. Ich halte mich an die Konvention, einen Wert ungleich 0 im Fehlerfalle zurückzugeben und dem Benutzer einen Hinweis für die korrekte Benutzung meiner Funktion zu zeigen (der eigentlich auf stderr und nicht stdout erscheinen sollte). Statt das Verzeichnis zu wechseln, packe ich den Pfad lieber mit in den Aufruf von glob. Da mir dieser eine Liste von Pfaden liefert, muss ich nicht selbst zählen, wie viele das sind. Das Ausgeben der Namen vor dem Umbenennen fand ich nicht sinnvoll, denn habe ich an dieser Stelle einen Fehler gemacht, kann ich eh das Script nicht schnell genug abbrechen. Ich habe daher ein "-v" für "verbose", also geschwätzig als Option eingeführt und entscheide damit, ob ich etwas ausgegeben haben will oder nicht. Bei der rename-Methode ist zu beachten, dass ich möglicherweise auch innerhalb des Pfads und nicht nur am Ende ersetze. Das ist ein Fehler, aber ich wollte jetzt nicht eine Suche mit regulären Ausdrücken einführen. Mein Tipp wäre, mal "endswith" als String-Methode anzuschauen und dann zu überlegen, wie man wohl einen neuen String ohne die alte Endung aber mit der neuen Endung bauen kann, wenn man die Länge des alten Strings kennt.

Stefan

Re: Python Script zum ändern von Dateiendungen

Verfasst: Donnerstag 5. Januar 2012, 14:47
von korkak
nomnom hat geschrieben:
ps: irgendwie übernimmt der die formatierung von den einrückungen nicht...
Das liegt daran, dass du deinen Code ausdrücklich in python-Tags schreiben musst.
  • `os.chdir(p)` ganz böse! ;-) Man erwartet von einem Skript nicht, dass es einfach das Verzeichnis wechselt, wenn man es aufruft.
  • Du kannst dir auch mal `os.walk` anschauen.
  • `string.replace(filename, e, n)` Da ist ein logischer Fehler drin. Da wird nicht nur die Dateiendung geändert … Außerdem solltest du lieber filename.replace(e, n) benutzen. Und wenn du eine Variable sowieso nur einmal verwendest, kannst du den Wert gleich der benutzenden Funktion übergeben.
  • Bei Python 2 ist `print` keine Funktion, sondern ein Statement! Du solltest `print` auch so behandeln, denn das sieht komisch aus:

    Code: Alles auswählen

    >>> print('foo', 'bar')
    ('foo', 'bar')
    >>> 

hi nomnom, danke für deine anmerkungen.

a) os.walk: leider habe ich keine ahnung wie ich das einbauen sollte anstelle von os.chdir.
b) filename.replace: das hab ich geändert und funktioniert, siehe unten.
c) welche variable meinst du, die ich direkt an die funktion übergeben soll weil ich sie nur einmal nutze?
d) was mache ich bei dem print befehl falsch, er scheint mir korrekt zu funktionieren, benutze gerade python 2.4.4 ?

entschuldige meine unwissenheit, befasse ich mich erst seit ca. einer woche mit programmierung bzw. python.

gruß korkak

Code: Alles auswählen

import os, glob, string
p = raw_input("Bitte den vollständigen Pfad eingeben: ")
if os.path.exists(p):
    e = raw_input("Welche Dateiendung, z.B.: .txt, soll geändert werden? ")
    n = raw_input("Wie lautet die neue Dateiendung, z.B.: .jpg? ")
    print(p, " : Pfad existiert!")
    os.chdir(p)
    filenames = glob.glob('*' + e)
    print("Folgende Dateien wurden gefunden:")
    for file in filenames:
        print(file)
    i = 0
    for filename in filenames:
        newfilename = filename.replace(e, n)
        os.rename(filename, newfilename)
        i = i + 1
    print(i, "Dateien wurden umbenannt.")
else:
    print(p, " : Pfad existiert nicht!")

Re: Python Script zum ändern von Dateiendungen

Verfasst: Donnerstag 5. Januar 2012, 15:13
von korkak
@stefan, auch dir ein großes danke, du hast das programm ja gleich neu geschrieben :D

allerdings stehen da soviele dinge drin die ich noch nicht kenne wie sys.argv, except valueerror und vor allem diese %d und %s verstehe ich nicht, da brächte ich noch ein paar extra kommentare was du da genau machst :oops:
ich werde mir das später nochmal ganz genau durchlesen und die informationen zu den funktionen die du da benutzt raussuchen.

danke und gruß
korkak

Re: Python Script zum ändern von Dateiendungen

Verfasst: Donnerstag 5. Januar 2012, 15:16
von nomnom
korkak hat geschrieben:a) os.walk: leider habe ich keine ahnung wie ich das einbauen sollte anstelle von os.chdir.
Ich dachte eher an os.walk statt glob.glob, aber ist eigentlich egal.
c) welche variable meinst du, die ich direkt an die funktion übergeben soll weil ich sie nur einmal nutze?
Es gibt nur eine … `newfilename`
d) was mache ich bei dem print befehl falsch, er scheint mir korrekt zu funktionieren
`print` ist keine Funktion. Schau dir an, wie sma `print` benutzt.
benutze gerade python 2.4.4 ?
Python 2.4 ist soweit ich weiß veraltet. Hat es irgendeinen speziellen Grund warum du Python 2.4 benutzt? Sonst solltest du Python 2.7 nutzen.

Re: Python Script zum ändern von Dateiendungen

Verfasst: Donnerstag 5. Januar 2012, 15:30
von Hyperion
Ich würde mir such mal smas Vorschlag angucken; da kannst Du einiges von lernen.

Re: Python Script zum ändern von Dateiendungen

Verfasst: Donnerstag 5. Januar 2012, 15:33
von sma
sys.argv ist eine Liste mit den Parametern, die einem Python-Programm in der Kommandozeile übergeben wurden. Meine nächste Zeile mit dem "in"-Operator macht sich zu nutze, dass der Teillisten-Operator [:1] niemals fehlschlägt und immer eine Teilliste liefert, ggf. eine leere Liste. In der Teilliste bestehend aus dem ersten Element von sys.argv oder eben der leeren Liste suche ich nach dem String "-v". Wenn er da ist, entferne ich das erste Element der Liste.

Mit try/except kann ich auf einen Fehler reagieren, den Python ansonsten melden würde. Wenn sys.argv nicht drei Elemente enthalt, kommt es zu einem ValueError bei der Dreifachzuweisung. An dieser Stelle will ich aber nicht, dass mein Programm mit dem Fehler abbricht, sondern einen Fehlertext ausgeben und selbst abbrechen. das kann man so lesen: Liebes Python, versuche mal die Zeile(n) hinter try: auszuführen. Geht das mit dem angegebenen Fehler schief, dann führe stattdessen die Zeile(n) hinter dem passenden except-Block aus (davon kann es mehrere geben). Ansonsten geht es nach dem letzten except-Block weiter.

Mit %s und dem "%"-Operator kann ich in einem String andere Strings einfügen. Dort wo "%s" wird dies durch die String-Repräsentation der hinter "%" aufgeführten Variable ersetzt. Da das ein String ist, ist er seine eigene String-Repräsentation, d.h. aus "rename: %s doesn't exist" und einer Variable path mit dem Wert "foo.txt" würde der String "rename: foo.txt doesn't exist" werden.

Gleiches gilt für %d, nur das erwartet eine Zahl, kein String.

Stefan

Re: Python Script zum ändern von Dateiendungen

Verfasst: Freitag 6. Januar 2012, 11:00
von korkak
@Stefan

jetzt habe ich einigermaßen verstanden wies das mit sys.argv funktioniert, es wird genutzt, wenn ich das script mit argumenten aufrufen will z.b. unter unix.

was ich vorhabe ist, weiter an diesem script zu arbeiten und lernen was noch möglich ist.
ich möchte es z.b. unter windwos starten können auf dem kein python installiert ist und es dazu zu einer .exe datei umwandeln. dann, falls es möglich ist, möchte ich einbauen das ein fenster(nicht dos) aufgeht, wo ich dann die infos zu pfad und dateieindungen eingeben kann.

sys.exit(1) habe ich jetzt drin falls der pfad nicht existiert.

ich habe auch versucht endswith einzubauen,funktionierte auf den ersten blick, dann habe ich eine datei mit namen "test.txt.date.txt" hinzugefügt um zu überpüfen ob es auch im negativfall funktioniert, doch leider bekomme ich dann die fehlermeldung:
WindowsError: [Error 2] Das System kann die angegebene Datei nicht finden.

Code: Alles auswählen

import os, glob, sys

p = raw_input("Bitte den vollständigen Pfad eingeben: ")

if not os.path.exists(p):
    print "%s Verzeichnis existiert nicht." % p
    sys.exit(1)

alt = raw_input("Welche Dateiendung, z.B.: .txt, soll geändert werden? ")
neu = raw_input("Wie lautet die neue Dateiendung, z.B.: .jpg? ")

if p.endswith(alt):
    names = glob.glob(os.path.join(p, "*" + alt))

print "Folgende Dateien wurden gefunden:"
print "---------------------------------" 
for file in names:
    print file
    
for file in names:
    new_name = file.replace(alt, neu)
    os.rename(file, new_name)

print "-----------------------------"    
print "%d Dateien wurden umbenannt." % len(names)



Re: Python Script zum ändern von Dateiendungen

Verfasst: Freitag 6. Januar 2012, 16:27
von darktrym
os.path.join fehlt

Re: Python Script zum ändern von Dateiendungen

Verfasst: Freitag 6. Januar 2012, 17:35
von lunar
@sma: Dein Beispiel verarbeitet die Argumente fehlerhaft. In "sys.argv[0]" steht der Name des Programms, nicht das erste Argument. Ist "verbose" falsch, enthält "path" mithin den Programmnamen. Ist "verbose" wahr, enthält "path" die Zeichenkette '-v'. Beides ist wohl kaum gewünscht. Ein gutes Beispiel, warum man lieber die Mittel der Standardbibliothek nutzt:

Code: Alles auswählen

from argparse import ArgumentParser

parser = ArgumentParser()
parser.add_argument('-v', action='store_true', dest='verbose')
parser.add_argument('path')
parser.add_argument('old_ext')
parser.add_argument('new_ext')
args = parser.parse_args()

if not os.path.exists(args.path):
    parser.error('%s does not exit' % path)    

names = glob.glob(os.path.join(args.path, "*" + args.old_ext))

for name in names:
    new_name = name.replace(args.old_ext, args.new_ext)
    os.rename(name, new_name)
    if args.verbose:
        print "rename: %s -> %s" % (name, new_name)

if args.verbose:
    print "rename: %d files renamed" % len(names)

Re: Python Script zum ändern von Dateiendungen

Verfasst: Freitag 6. Januar 2012, 23:20
von korkak
darktrym hat geschrieben:os.path.join fehlt

meinst du das in bezug auf die nicht funktionierende funktion:

Code: Alles auswählen

if p.endswith(alt):
    names = glob.glob(os.path.join(p, "*" + alt))
ich glaube eher ich benutze dieses endswith falsch...

Re: Python Script zum ändern von Dateiendungen

Verfasst: Freitag 6. Januar 2012, 23:48
von BlackJack
@korkak: Du benutzt das an der völlig falschen Stelle. `p` ist der Pfad den der Benutzer eingegeben hat. Welchen Sinn sollte das machen *den* darauf zu prüfen ob er mit der alten Dateieendung endet!?

Re: Python Script zum ändern von Dateiendungen

Verfasst: Montag 9. Januar 2012, 14:16
von korkak
BlackJack hat geschrieben:@korkak: Du benutzt das an der völlig falschen Stelle. `p` ist der Pfad den der Benutzer eingegeben hat. Welchen Sinn sollte das machen *den* darauf zu prüfen ob er mit der alten Dateieendung endet!?
BlackJack, ich wollte sichergehen, das wirklich nur dateien mit der endung z.b. "txt" geändert werden und nicht welche, die zufällig im namen ein "txt" haben. dies wollte ich mit endswith sicherstellen, offensichtlich benutze ich es falsch oder an der falschen stelle, kannst du mir einen tipp geben wie ich es richtig einsetze?

danke und gruß
korkak

Re: Python Script zum ändern von Dateiendungen

Verfasst: Montag 9. Januar 2012, 15:21
von EyDu
Hallo.

BlackJack hat dir dir Lösung doch bereits geschrieben. Du hast in ``p`` den eingegebenen Pfad gespeichert, der endet natürlich nicht mit der richtigen Dateiendung. Du bist an dem Ergebnis von ``glob.glob`` interessierst, da die darin enthaltenden Elemente eine bestimmte Endung haben sollen. Das brauchst du aber nicht zu prüfen, da ``glob.glob`` das selber bereits macht.

Sebastian

Re: Python Script zum ändern von Dateiendungen

Verfasst: Dienstag 10. Januar 2012, 11:10
von korkak
sorry, da habt ihr natürlich vollkommen recht, jetzt verstehe ich es.
mit glob.glob suche ich mir ja eigentlich schon die richtigen dateien raus.

Code: Alles auswählen

names = glob.glob(os.path.join(p, "*." + alt))
unwahrscheinlich aber dennoch möglich wäre aber doch z.b. folgende situtation:
wenn diese dateien im verzeichnis wären:

test.txt
test2.txt
test.txt.nocheintest.txt

dann würde ich die datei "test.txt.nocheintest.txt" z.b. ändern in "test.jpg.nocheintest.jpg" und das wäre ja nicht in ordnung.
deswegen wollte ich die funktion endswith irgendwie einbauen, so das wirklich nur die endung geändert wird, wie bekommt man das hin?

danke und gruß
korkak

Re: Python Script zum ändern von Dateiendungen

Verfasst: Dienstag 10. Januar 2012, 11:58
von cofi
Das ist aber ein Problem des Umbenennens und nicht des Sicherstellens, ob deine Datei tatsaechlich in '.txt' endet, denn das macht `glob` schon.

Hier ein kleiner Trace als Anregung für ein passendes Umbenennen:

Code: Alles auswählen

In [1]: import os

In [2]: name = 'test.txt.nocheintest.txt'

In [3]: os.path.splitext(name)
Out[3]: ('test.txt.nocheintest', '.txt')

In [4]: basename, _ = os.path.splitext(name)

In [5]: new_extension = '.jpg'

In [6]: new_name = basename + new_extension

In [7]: new_name
Out[7]: 'test.txt.nocheintest.jpg'

Re: Python Script zum ändern von Dateiendungen

Verfasst: Dienstag 10. Januar 2012, 15:05
von korkak
@cofi

ich habe versucht deinen vorschlag umzusetzen und es funktioniert offensichtlich auch, seht ihr vielleicht sonst noch einen fehler/problem?

Code: Alles auswählen

import os, glob, sys

p = raw_input("Bitte den vollständigen Pfad eingeben: ")

if not os.path.exists(p):
    print "Das Verzeichnis '%s' existiert nicht." % p
    sys.exit(1)

alt = raw_input("Welche Dateiendung, z.B.: 'txt', soll geändert werden? ")
neu = raw_input("Wie lautet die neue Dateiendung, z.B.: 'jpg'? ")

names = glob.glob(os.path.join(p, "*." + alt))

print "Folgende Dateien wurden gefunden:"
print "---------------------------------"

for file in names:
    print file

for file in names:
    basename, ext = os.path.splitext(file)
    new_name = basename + "." + neu
    os.rename(file, new_name)
        
print "-----------------------------"    
print "%d Dateien wurden umbenannt." % len(names)

danke und gruß
korkak

Re: Python Script zum ändern von Dateiendungen

Verfasst: Dienstag 10. Januar 2012, 21:25
von nomnom
Problem: Du benutzt immer noch nicht die [ python]-Tags. :P Die globalen Variablen könntest du IMHO auch loswerden und das eher in Funktionen auslagern, sonst fragt man sich plötzlich wo z. B. ``neu`` herkommt.

Code: Alles auswählen

for file in names:
    print file
könntest du durch ``print "\n".join(names)`` verkürzen, und die andere ``for``-Schleife könnte man IMHO auch kürzer gestalten:

Code: Alles auswählen

for x in name:
    os.rename(x, os.path.splitext(x)[0]+'.'+neu)

Re: Python Script zum ändern von Dateiendungen

Verfasst: Mittwoch 11. Januar 2012, 07:26
von korkak
nomnom hat geschrieben:Problem: Du benutzt immer noch nicht die [ python]-Tags. :P Die globalen Variablen könntest du IMHO auch loswerden und das eher in Funktionen auslagern, sonst fragt man sich plötzlich wo z. B. ``neu`` herkommt.

Code: Alles auswählen

for file in names:
    print file
könntest du durch ``print "\n".join(names)`` verkürzen, und die andere ``for``-Schleife könnte man IMHO auch kürzer gestalten:

Code: Alles auswählen

for x in name:
    os.rename(x, os.path.splitext(x)[0]+'.'+neu)
Hey, danke das du dir noch mal die mühe gemacht hast :P

ich habe da aber noch verständnisfragen:

1) Du benutzt immer noch nicht die [ python]-Tags.
was meinst du damit genau, meinst du damit die schreibweise der python programmierung?
ich versuche alles so umzusetzen wie es in den tutorials steht, allerdings ist deine schreibweise irgendwie kürzer und einfacher :wink:

2) Die globalen Variablen könntest du IMHO auch loswerden und das eher in Funktionen auslagern...
Wie muss ich mir das vorstellen, soll ich es so umsetzen?

Code: Alles auswählen

def end_alt():
	alt = raw_input("Welche Dateiendung, z.B.: 'txt', soll geändert werden? ")
end_alt()
wahrscheinlich nicht, bisher hast du mir immer aufgezeigt wie man alles kürzer schreiben kann und das würds ja eher länger machen...

3)

Code: Alles auswählen

print "\n".join(names)
hab ich umgesetzt, klappt astrein!

4)

Code: Alles auswählen

for x in names:
    os.rename(x, os.path.splitext(x)[0]+'.'+neu)
auch umgesetzt und hat mich am meisten begeistert, ich habe 3 stunden gebraucht bis ich es auf meine weise hinbekommen habe und jetzt sehe ich wie einfach man es wirklich machen kann, genial :mrgreen:

danke und gruß
korkak