Alle Dateien mit gleichem Dateinamenanfang öffnen

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.
BlackJack

@01detlef: Ich würde dazu die Datei komplett kopieren und dann mit den Methoden `seek()` und `truncate()` die letzten fünf Bytes bei der Kopie abschneiden.
01detlef
User
Beiträge: 105
Registriert: Montag 10. Mai 2010, 21:59

Hallo ,
also mit seek und truncate ist mir das nicht klar. Ich dachte jetzt an sowas:

string = 'Name_i=5_12345.txt'
tsplit(string,('_','.'))

Und nun sollen die ersten beiden Teile als Name dienen und die Dateiendung gleich bleiben (txt-file). Also ich möchte mit join() einzelne Teile wieder zusammensetzen?

detlef
BlackJack

@01detlef: Also willst Du doch nichts am Dateiinhalt ändern‽ 5 Zeichen vom Dateinamen entfernen ist etwas anderes als 5 Zeichen von der Datei entfernen. Da musst Du etwas präziser sein.

Bei dem Beispiel vermischt Du schon wieder Zeichenketteninhalt mit Namen oder „Pseudonamen”. Oder ist 'Name_i=' tatsächlich Bestandteil eines Dateinamens‽

Zum auftrennen von Pfad und Dateinamenserweiterung gibt es in `os.path` eine Funktion: `splitext()`.

Was sind „die ersten beiden Teile”? Und willst Du hier tatsächlich 5 Zeichen entfernen, oder vielleicht doch *6*, nämlich auch den '_' vor der 5stelligen Zahl? Hat der Teil immer 5 Stellen, oder möchtest Du allgemein alles nach dem letzten '_' entfernen? Statt fiktiver Funktionen wie `tsplit()` schau doch mal was Zeichenketten tatsächlich an Methoden haben und vor allem auch was für Argumente sie entgegen nehmen. Man kann den Funktionen zum Aufteilen nämlich üblicherweise auch mitgeben wie oft maximal geteilt werden soll.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Auch wenn Du meinen ersten Beitrag ignoriert hast, will ich mal nicht so sein und schalte mich noch mal mit ein ;-)

Suchst Du vielleicht `os.rename`? Damit kannst Du Dateien umbenennen...

Deine Ersetzungsregel ist mir noch nicht klar, BlackJack fragte da ja auch schon. Ggf. kann man da auch mit einem RegExp arbeiten. Ohne präzise Angaben kann man da eben nur wage Tipps geben.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
01detlef
User
Beiträge: 105
Registriert: Montag 10. Mai 2010, 21:59

Hallo,

okay dann versuche ich mal die Problematik zu beschreiben. Ich habe viele Dateien mit einem Namen wie folgt aufgebaut:
Name_i=5_12345.txt
Name_i=10_18372.txt
Name_i=15_76382.txt
usw...

Ich möchte nur den Namen der Dateien ändern. Es sollen die letzten sechs (mit _) gelöscht werden und wieder als .txt abgespeichert werden. In der Datei soll nix geändert werden. Resultat:
Name_i=5.txt
Name_i=10.txt
Name_i=15.txt
usw...

Ist das verständliche so?

detlef
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Auch wenn Du nun meine Nachfrage erneut ignoriert hast, schrieb ich Dir doch schon die Lösung. `os.rename` ist Dein Freund.

Da es *immer* exakt sechs Zeichen sind, hast Du die Lösung schon im Link von /me erhalten... aber ich spiele mal Vorleser:

Code: Alles auswählen

In [2]: os.path.splitext("Name_i=5_12345.txt")
Out[2]: ('Name_i=5_12345', '.txt')

In [3]: filename, ext = os.path.splitext("Name_i=5_12345.txt")

In [4]: filename[:-6]
Out[4]: 'Name_i=5'

In [5]: "%s%s" % (filename[:-6], ext)
Out[5]: 'Name_i=5.txt'
Dazu braucht es - neben dem Wissen um `os.path.splitext`, was Dir BlackJack ja nannte - nur "Slicing". Und das ist absolutes Grundlagenwissen!
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
01detlef
User
Beiträge: 105
Registriert: Montag 10. Mai 2010, 21:59

Hallo,

vielen Dank für die Hilfe. Sollte man die beiden Teile (filename[:,-6] und ext) mit join wieder verbinden, das habe ich irgendwo mal gelesen?

Wenn ich den neuen Namen dann zusammengesetzt habe, muss man dann nochmal extra sagen, dass die Datei gespeichert wird unter dem neuen Namen?

Code: Alles auswählen

os.renames(old,new)
01detlef
User
Beiträge: 105
Registriert: Montag 10. Mai 2010, 21:59

Hallo,

also ich dachte da nun an sowas:

Code: Alles auswählen

for file in glob.glob('Name*'):
       filename,ext = os.path.splitext(file)
       newfilename = ''.join([filename,ext])
       os.renames(filename,newfilename)
Macht das soweit Sinn?

detlef
Zuletzt geändert von Hyperion am Sonntag 27. Mai 2012, 11:58, insgesamt 1-mal geändert.
Grund: Code in Python-Code Tags gesetzt.
BlackJack

@01detlef: Mal abgesehen davon, dass ich statt `join()` hier den ``+``-Oerator verwenden würde, überlege doch mal selbst ob das Sinn macht. Mal angenommen es wären keine Fehler drin, würdest Du den Namen zerlegen und wieder zusammen setzen und dann von welchem Namen zu welchem Namen umbenennen‽

Gehe in Gedanken durch was jede Anweisung zur Laufzeit macht, spiele also selbst Python-Interpreter. Stell Dir selbst die Frage „Welcher Wert ist wann an welchen Namen gebunden?” und beantworte sie Dir. Dann vergleichst Du Deine Erwartungen mit der Realität. Zum Beispiel in dem Du ein paar ``print``-Anweisungen einstreust um die Werte zu überprüfen. Probiere an einem Verzeichnis mit Testdateien mit entsprechenden Namen.

Der Name `file` ist irreführend, weil `glob()` keine Datei-Objekte, sondern Zeichenketten liefert, die Pfad- bzw. Dateinamen enthalten.

Vielleicht solltest Du auch nicht so viel Quelltext schreiben ohne ihn auszuprobieren. Und ja, vier Zeilen können für einen Anfänger schon viel sein. Entwickle den Code nicht, in dem Du viel schreibst und dann hier nachfragst, sondern in dem Du das selber Stück für Stück entwickelst, und jeden Schritt testest und erst weiteren, neuen Quelltext dazu schreibst, wenn der bisherige das (Teil)Ergebnis liefert, welches Du haben wolltest.

Das fängt an mit einem Grundgerüst:

Code: Alles auswählen

#!/usr/bin/env python
from glob import glob


def main():
    for path in glob('Name*'):
        print path


if __name__ == '__main__':
    main()
Laufen lassen und schauen ob das bis dahin das tut was es soll:

Code: Alles auswählen

bj@s8n:~/tmp$ ls Name*
Name_i=10_18372.txt  Name_i=15_76382.txt  Name_i=5_12345.txt
bj@s8n:~/tmp$ ./test.py
Name_i=5_12345.txt
Name_i=15_76382.txt
Name_i=10_18372.txt
Nächster Schritt ist das zerlegen des Dateinamens in Name und Erweiterung:

Code: Alles auswählen

    for path in glob('Name*'):
        old_filename, extension = os.path.splitext(path)
        print old_filename, '|', extension
Testlauf:

Code: Alles auswählen

bj@s8n:~/tmp$ ./test.py
Name_i=5_12345 | .txt
Name_i=15_76382 | .txt
Name_i=10_18372 | .txt
Dann setzt Du beides wieder zusammen:

Code: Alles auswählen

    for path in glob('Name*'):
        old_filename, extension = os.path.splitext(path)
        new_filename = old_filename + extension
        print old_filename, '->', new_filename
Testlauf:

Code: Alles auswählen

bj@s8n:~/tmp$ ./test.py
Name_i=5_12345 -> Name_i=5_12345.txt
Name_i=15_76382 -> Name_i=15_76382.txt
Name_i=10_18372 -> Name_i=10_18372.txt
An der Stelle kann man vielleicht auch schon erahnen was die Sinnhaftigkeit eines Umbenennens von `old_filename` nach `new_filename` angeht. Dann sollte man hier nicht mit `os.rename()` weiter machen, sondern erst einmal dafür sorgen, dass die Daten bis zu diesem Punkt im Programmablauf sinnvolle Werte annehmen.

Falls das Problem nicht offensichtlich war, wird es spätestens beim Versuch umzubenennen klar:

Code: Alles auswählen

    for path in glob('Name*'):
        old_filename, extension = os.path.splitext(path)
        new_filename = old_filename + extension
        print old_filename, '->', new_filename
        os.rename(old_filename, new_filename)
Testlauf:

Code: Alles auswählen

bj@s8n:~/tmp$ ./test.py
Name_i=5_12345 -> Name_i=5_12345.txt
Traceback (most recent call last):
  File "./test.py", line 15, in <module>
    main()
  File "./test.py", line 11, in main
    os.rename(old_filename, new_filename)
OSError: [Errno 2] No such file or directory
Wenn man länger programmiert und die Erfahrung wächst, werden die Quelltextabschnitte grösser, die man zwischen Testläufen schreiben kann, ohne dass man zu viele Fehler in den Abschnitt einbaut. Aber für den Anfang kann es Sinn machen jede Zeile zu prüfen ob sie den Erwartungen entspricht, bei komplexeren Sachen sogar für Teilausdrücke innerhalb einer Zeile.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Du solltest Code mal in einer Shell ausprobieren! So macht das doch gar keinen Sinn. `filename` ist bei Dir ja gar nicht der *alte* Dateiname, sondern ein "verstümmelter" Teil davon!

Im übrigen solltest Du im Kopf der `for`-Schleife nicht den Namen `file` benutzen. Das ist ja gar kein File-Objekt, sondern ein Dateiname. Also benutze doch an dieser Stelle den Namen `filename`. Weiter unten nennst Du das dann eben `root`, wie es in der Doku (`os.path.splitext`) vorgeschlagen wird.

Bei Python 2.x solltest Du `file` generell nicht benutzen, da Du damit eine Built-in Funktion überschreibst.

`str.join()` benutzt man immer dann, wenn man ein `Iterable` mit String-Objekten hat, typischer Weise oftmals eine Liste. Wenn man diese aber erst künstlich generiert, wie Du es tust, dann ist das der falsche Weg. Ich habe Dir ja eine Möglichkeit bereits angegeben, Du kannst auch die `str.format()`-Methode nutzen.

Ach ja, meine Frage hast Du schon wieder nicht beantwortet :-D

PS: BlackJack war schneller, ich lasse das dennoch mal so stehen, insbesondere, weil die Frage ja noch im Raum steht... ;-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
01detlef
User
Beiträge: 105
Registriert: Montag 10. Mai 2010, 21:59

@Hyperion: Meinst du die Frage, um was für ein Programm es sich handelt? Es soll ein alias-Befehl aufgerufen werden, also nicht mv oder cp.

@Blackjack: Vielen Dank. Ich wollte rename-Aufruf verwenden, weil ich nicht so ganz verstehe, warum der Dateiname sofort geändert wird, ohne nochmal direkt zu sagen, dass er "gespeichert" werden soll.

Vielen Dank für eure Hilfe.

detlef
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

01detlef hat geschrieben:@Hyperion: Meinst du die Frage, um was für ein Programm es sich handelt? Es soll ein alias-Befehl aufgerufen werden, also nicht mv oder cp.
Ok. Oftmals wollen User hier Dinge per Shell lösen, für die Python direkt Funktionalität anbietet. Also etwas die grundlegende Dinge wie Kopieren, Verschieben, usw., aber auch Dinge wie `tar`, `zip`, das Erstellen von Prüfsummen uvm. So etwas löst man dann eben besser nicht über den Umweg `subprocess`. Daher fragte ich nach :-)

Dein "Alias" kann natürlich immer noch Dinge beinhalten, auf die das zutrifft ;-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
BlackJack

@01detlef: Bei „gefährlichen” Sachen sollte man auch immer überlegen was zum Beispiel passiert wenn es mehrfach aufgerufen wird, oder wenn schon Zieldateien mit gleichen Namen existieren.
01detlef
User
Beiträge: 105
Registriert: Montag 10. Mai 2010, 21:59

Vielen Dank für eure Hilfe. Ich muss nochmal nachfragen, weil ich das immer noch nicht verstehe, wieso das so funktioniert.
new_filename = old_filename + extension
print old_filename, '->', new_filename
Ich habe mir dann die neuen Namen zusammengesetzt, aber wieso weiss er dann automatisch, dass die auch so direkt umbenannt wird. Also ich habe den neuen String, aber wieso wird die Datei dann auch direkt umbenannt?

detlef
BlackJack

@01detlef: Da wird doch keine Datei umbenannt‽ Das macht `os.rename()`.
01detlef
User
Beiträge: 105
Registriert: Montag 10. Mai 2010, 21:59

Hallo,

aber dann verstehe ich den Beitrag von BlackJack nicht. Er schreibt ja, dass bei rename eine Fehlermeldung auftritt. Es ist also richtig, dass der neue Name noch nicht der Datei zugeordnet ist? Also muss ich doch noch ein rename machen?!

detlef
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Ich verstehe nun wiederum Deinen Beitrag nicht und bin verwirrt!

`os.rename` benennt eine Datei um. Fertig. Natürlich tut es das nicht, wenn ein Fehler auftritt. Lies Dir dazu noch mal dieses Posting von mir durch, insbesondere den ersten Absatz! BlackJack hatte den Fehler in seinem ausführlichem Posting darüber *extra* so gelassen, damit Du selber darauf kommst. (Nehme ich mal an)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
01detlef
User
Beiträge: 105
Registriert: Montag 10. Mai 2010, 21:59

Hallo,

also ich hatte das so verstanden, dass ich mit

Code: Alles auswählen

    for path in glob('Name*'):
        old_filename, extension = os.path.splitext(path)
        new_filename = old_filename + extension
        print old_filename, '->', new_filename
den neuen Namen definieren kann und ebenfalls der neue Dateiname schon abgespeichert ist?! Weil mit dem os.rename tritt ja ein Fehler auf???

detlef
Zuletzt geändert von Hyperion am Montag 28. Mai 2012, 16:29, insgesamt 1-mal geändert.
Grund: Code in Python-Code Tags gesetzt.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

01detlef hat geschrieben: also ich hatte das so verstanden, dass ich mit

Code: Alles auswählen

for path in glob('Name*'):
    # hier bekommst Du zwei Strings
    old_filename, extension = os.path.splitext(Pathos)
    # hier baust Du einen neuen String zusammen
    new_filename = old_filename + extension
    # hier gibst Du den String aus
    print old_filename, '->', new_filename
den neuen Namen definieren kann und ebenfalls der neue Dateiname schon abgespeichert ist?!
Hä? Wie sollte das gehen!?! s. meine Kommentare im Code! An welcher Stelle sollte so etwas passieren? Python und Programmiersprachen i.A. sind doch nichts "magisches" und verfügen über hellseherische Fähigkeiten von dem, was Du erreichen willst! Du schreibst *nirgends* irgend etwas in Deinen Code, welches eine Datei auf Deiner Festplatte umbenennt! Wie ich Dir ja schon unlängst schrieb, benutzt man dafür `os.rename`.
01detlef hat geschrieben: Weil mit dem os.rename tritt ja ein Fehler auf???
Ja und was sagt uns das? Denk mal drüber nach und *lies* Dir die von mir bereits genannte Stelle noch mal durch. Sollte das immer noch nicht klar sein, dann schau Dir die Ausgabe mal *exakt* an! Dann solltest Du darauf kommen, wieso dieser Fehler auftritt. Und wenn das nicht hilft, dann überprüfe eben mal in einer Shell, ob Du die Datei, die Du in `old_filename` vermutest, auf Deiner Platte findest.

Als letzten Tipp: Dein OS kann ja nur Dinge umbenennen, die auch existieren ;-)

Und als letzten Hinweis: Bitte benutze für Python-Code die Python-Code-Tags: [ code=python ] [ /code ] (ohne die Leerzeichen)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
01detlef
User
Beiträge: 105
Registriert: Montag 10. Mai 2010, 21:59

Hallo,

meinst du, weil die Namen new und old genau identisch sind? Also dann würde ich das so ändern:

Code: Alles auswählen

    for path in glob('Name*'):
        old_filename, extension = os.path.splitext(path)
        new_filename = old_filename[:-6] + extension
        print old_filename, '->', new_filename
        os.rename(old_filename, new_filename)
Meckert rename also, wenn die beiden Dateinamen identisch sind? Ich dachte, das wird missachtet.

detlef
Antworten