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.
01detlef
User
Beiträge: 105
Registriert: Montag 10. Mai 2010, 21:59

Hallo zusammen,

ich habe in einem Ordner mehrere Dateien mit gleichem Namenanfang liegen (die Endungen variieren) und möchte die Namen einlesen. Es geht nicht um den Inhalt der Datei, sondern wirklich nur um den Namen der Dateien. Kann ich nun eine Schleife definieren, die alle Dateien mit einem gewissen Dateinamenanfang einliest (den Dateinamen)? Ich kenne das nur, wenn alle Textfiles oder so eingelesen werden sollen:

fobj = glob.glob("*.txt")

Geht das auch anders herum?

fobj = glob.glob("*Name.")

?

detlef
BlackJack

@01detlef: Das Sternchen steht für „beliebige Zeichen”, also wäre andersherum 'Name*', und ja das geht.

Code: Alles auswählen

In [1315]: glob.glob('forum*')
Out[1315]: 
['forum8.py',
 'forum.txt',
 'forum3.py',
 'forum2.py',
 'forum4.py',
 'forum.txt~',
 'forum5.py~',
 'forum5.py',
 'forum.pyc',
 'forum2.py~',
 'forum9.py~',
 'forum6.py',
 'forum10.py',
 'forum8.py~',
 'forum3.py~',
 'forum6.py.bak',
 'forum.py',
 'forum6.pyc',
 'forum.py~',
 'forum4.py~',
 'forum6.py~',
 'forum7.py~',
 'forum7.pyc',
 'forum10.py~',
 'forum9.py',
 'forum7.py']
01detlef
User
Beiträge: 105
Registriert: Montag 10. Mai 2010, 21:59

Hallo,

das hört sich schon mal gut an. Also bei mir sieht das so aus, dass die Dateien
Name.3.txt
Name.2.dat
heißen und nacheinander eingelesen werden sollen (also der Name jeder Datei). Dieser Titel soll dann in den Aufruf
subprocess.call(['bla Titel'], shell=True)
in jedem Schleifendurchlauf eingefügt werden.

Also erster Durchlauf wäre dann
subprocess.call(['bla Name.3.txt'], shell=True)

Zweiter Durchlauf
subprocess.call(['bla Name.2.dat'], shell=True)

Für einzelne Aufrufe funktioniert alles, nur macht mir die Schleife Probleme. Hat da jemand einen Tipp, sollte es eine while-Schleife sein?

detlef
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

01detlef hat geschrieben:Für einzelne Aufrufe funktioniert alles, nur macht mir die Schleife Probleme.
Entweder steckt mehr hinter dieser Frage als ich erkennen kann oder du kämpfst noch ein wenig mit den Grundlagen.
Die Basis wäre für mich hier so etwas:

Code: Alles auswählen

for name in glob.glob('*'):
    print name
01detlef
User
Beiträge: 105
Registriert: Montag 10. Mai 2010, 21:59

Ich kämpfe noch mit den Grundlagen!!

Code: Alles auswählen

import subprocess
import glob

for name in glob.glob('Name*'):
     print name
     subprocess.call(['bla name'], shell=True)
Also das funktioniert leider so noch nicht. Der String in name soll dann nacheinander im subprocess stehen, also um den Befehl auszuführen. Wieso geht das aber so nicht?
In name sind die richtigen Namen, aber sie werden nicht übergeben, so dass der Befehl falsch wird...

detlef
Zuletzt geändert von Anonymous am Freitag 25. Mai 2012, 11:42, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Code-Tags gesetzt.
karolus
User
Beiträge: 141
Registriert: Samstag 22. August 2009, 22:34

Hallo
Du möchtest vmtl.

Code: Alles auswählen

for name in glob.glob('Name*'):
     print name
     subprocess.call(['bla', name ], shell=True)
Karo
BlackJack

@01detlef: Natürlich funktioniert das so nicht. Wenn das so ginge das Python in Zeichenketten einfach so Teile ersetzt die ausserhalb einer Zeichenkette einen Namen darstellen, müsste man ja ständig aufpassen was man in Zeichenketten schreibt und wie man seine Namen wählt, damit da auch ja nie etwas aus versehen ersetzt wird.

Wenn Du mit den Grundlagen kämpfst, solltest Du vielleicht erst einmal ein Tutorial durcharbeiten. Zum Beispiel das in der Python-Dokumentation. Dann lernst Du den Umgang mit den Grunddatentypen.

``shell=True`` ist übrigens unschön. Man sollte an der Stelle lieber eine Liste mit Programm und Argumenten übergeben und die unnötige Shell zwischen drin auslassen. Dann braucht man sich auch keine Gedanken mehr über besondere Zeichen in den Pfad-/Dateinamen machen.
01detlef
User
Beiträge: 105
Registriert: Montag 10. Mai 2010, 21:59

Hallo,

das klappt leider auch nicht. Der Linux-Befehl, den ich aufrufen möchte, hat zwei Argumente:

Code: Alles auswählen

Befehl Arg1 Arg2
Also subprocess.call(['Befehl Arg1]) bleiben immer gleich, nur Arg2 soll immer einen anderen Dateinamen haben.

detlef
01detlef
User
Beiträge: 105
Registriert: Montag 10. Mai 2010, 21:59

Ok,

habe das nun hinbekommen:

Code: Alles auswählen

import subprocess
import glob

for arg2 in glob.glob('Wort*'):
     print arg2
     befehl = '...'
     arg1 = '....'
     command  = befehl+' '+arg1+' '+arg2
     subprocess.call(command, shell=True)
Aber das mit shell=True ist mir nicht klar, was daran ein Problem ist?

detlef
BlackJack

@01detlef: Bei ``shell=True`` wird eine Shell gestartet und in der wird die Zeichenkette als Kommandoeingabe ausgeführt. Das bedeutet die Zeichenkette muss von der Shell verstanden werden. Das kann zum einem zu Problemen führen wenn in den eingesetzten Werten für Dateinamen Zeichen enthalten sind, die eine besondere Bedeutung für die Shell haben, und zum anderen zu einem Sicherheitsproblem wenn andere die Kontrolle über die Daten haben können, die dort eingesetzt werden. Bei Deinem Beispiel wäre eine Datei mit dem Namen 'Wort; rm -rf ~/nur_zur_sicherheit' ohne den '/nur_zur_sicherheit'-Teil ziemlich unangenehm.

Da es in der Regel nicht schwieriger ist, es ohne die Shell zu lösen, sollte man sich das gar nicht erst angewöhnen.

Bei einer Liste als Argument musst Du eine Liste mit Einzelargumenten angeben so wie die Shell eine Befehlszeile aufteilen würde. Jedes Element ist *ein* Argument. Und das erste Element ist der Programmname. Wenn Du also ``['Befehl Arg1', 'Arg2']`` übergibst, dann ist 'Befehl Arg1' der Programmname — und so ein Programm hast Du wahrscheinlich eher nicht auf dem Rechner. Und auch Optionen wie ``--encoding utf8`` wären *zwei* Argumente.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Um was für ein Programm handelt es sich denn? Für viele Standardprogramme a la `cp` oder `mv` gibt es ja in Python fertige Funktionen in der Standard-Lib, also z.B. `shutils`, `os` usw. Nur mal so zur Info... :-)
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

Vielen Dank, also das funktioniert alles so weit ganz gut. Jetzt habe ich aber noch ein Problem, dass ich die Dateinamen "bearbeiten" möchte vorher.

Kann man den Dateinamen einlesen, dann z.B. die jetzten 5 Stellen abschneidet und dann damit weiterarbeitet (abspeichert) mit dem neuen Dateinamen?

detlef
Dav1d
User
Beiträge: 1437
Registriert: Donnerstag 30. Juli 2009, 12:03
Kontaktdaten:

Du solltest dir mal die Grundlagen anschauen.
Du iterierst mit der For-Schleife über jeden Dateinamen, also kannst du diesen bevor du ihn mit subprocess als Argument übergibst auch verändern...
the more they change the more they stay the same
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

01detlef hat geschrieben:Kann man den Dateinamen einlesen, dann z.B. die jetzten 5 Stellen abschneidet und dann damit weiterarbeitet (abspeichert) mit dem neuen Dateinamen?
Schau dir mal Strings im Tutorial an.

Wir helfen dir hier gerne weiter. Das Tutorial gibt dir aber erst einmal einen grundlegenden Überblick über die Möglichkeiten von Python.
01detlef
User
Beiträge: 105
Registriert: Montag 10. Mai 2010, 21:59

Hallo,

ok, ich gucke mir nun ersmal die Grundlagen zu Strings an, aber ich meine das wie folgt:

Die Datei soll eingelesen werden wie oben, dann die letzten 5 Zeichen abschneiden, abspeichern unter neuem Namen und dann den Befehl ausführen.

Es muss ja erst abgespeichert werden, sonst funktioniert der Befehl zum Ausführen nicht...

detlef
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
Antworten