Problem:
Die Schleife läuft, bis sie auf ein Verzeichnis trifft bei dem ein
'Permission denied' ausgelöst wird. In C würde ich das einfach mit einem
i++ in der Schleife abfangen.
Frage, wie kann ich der obigen FOR-Schleife mitteilen, dass sie im
Fehlerfall einfach mit dem nächsten Listenglied fortfahren soll?
continue does not work.
Würde vermutlich funktionieren, denke ich. Mich interessiert aber nach
wie vor, ob es im obigen Bsp. eine Möglichkeit gäbe, einen Schritt in
der Rekursion zu überspringen
Matthias schrieb:> Problem:> Die Schleife läuft, bis sie auf ein Verzeichnis trifft bei dem ein> 'Permission denied' ausgelöst wird.
Das sollte mit dem geposteten Code nicht passieren?!? Kannst Du Dein
Problem vielleicht etwas genauer beschreiben?
@Sheeva Plug
Code steht ja schon oben. Lasse ich try/except weg kommt es im
Verzeichnis /usr/lib/ssl zu einem Fehler, nämlich, wenn es zu 'private'
gelangt. Das ist ein link in die etc..., aber auch egal.
***Fehlermeldung***
for name in os.listdir(dir):
PermissionError: [Errno 13] Permission denied: '/usr/lib/ssl/private'
Kann man hinterher ja noch alles verfeinern, so dass auch Links und
Berechtigungen mit einbezogen werden. Erst einmal geht es mir aber um
etwas viel simpleres, nämlich wie ich einen Durchlauf in der
FOR-Schleife überspringe.
>Das sollte mit dem geposteten Code nicht passieren?!?
except bewirkt im konkreten Fall, dass die Schleife an genau der
besagten Stelle endet, was sie aber nicht soll.
Hab das jetzt mal ausprobiert. Bei mir funzt deine Funktion wie sie soll
(ohne Fehlermeldung). Nur wenn ich sie direkt mit "/etc/ssl/private"
aufrufe, kommt die von dir zitierte Fehlermeldung, was nicht verwundert,
weil der äußerste Aufruf vom os.listdir nicht von einem try-except
geschützt wird.
Matthias schrieb:> @Sheeva Plug>> Code steht ja schon oben. Lasse ich try/except weg kommt es im> Verzeichnis /usr/lib/ssl zu einem Fehler, nämlich, wenn es zu 'private'> gelangt. Das ist ein link in die etc..., aber auch egal.>> ***Fehlermeldung***> for name in os.listdir(dir):> PermissionError: [Errno 13] Permission denied: '/usr/lib/ssl/private'
Klar: ohne Exceptionhandling bricht der Code an der Stelle ab, wo Du ein
Listing aus einem Verzeichnis lesen willst, welches Du nicht lesen
darfst. Das ist ja auch vollkommen richtig so.
> Kann man hinterher ja noch alles verfeinern, so dass auch Links und> Berechtigungen mit einbezogen werden.
Das wäre eher un-pythonisch. Klar kannst Du mit den Funktionen aus dem
os-Modul die Permissions abfragen, wie man das in C/C++ und den meisten
anderen Sprachen machen würde. Aber der Python-Weg ist hier ein anderer:
probier's einfach aus und reagiere korrekt auf mögliche Exceptions. Das
erfordert allerdings, die Exception an der richtigen Stelle zu fangen.
Dein try/except ist dafür also genau das Richtige.
> Erst einmal geht es mir aber um> etwas viel simpleres, nämlich wie ich einen Durchlauf in der> FOR-Schleife überspringe.
Ich fürchte, das ist der große Irrtum: darum geht es gar nicht.
>>Das sollte mit dem geposteten Code nicht passieren?!?>> except bewirkt im konkreten Fall, dass die Schleife an genau der> besagten Stelle endet, was sie aber nicht soll.
Hier bei mir bricht Dein Code nur ab, wenn ich für das oberste
Verzeichnis -- also das, was beim ersten Aufruf von scan_dir() übergeben
wird -- keine Leserechte habe -- kurz gesagt: Für
scan_dir('/usr/lib/ssl') funktioniert Dein Code, weil ich Leserechte für
/usr/lib/ssl/ habe, für scan_dir('/usr/lib/ssl/private/') wirft Dein
Code eine Exception, weil ich darauf nicht lesen darf. Um diesen kleinen
Fehler zu beheben, gehört der Aufruf von os.listdir() in den try-Block:
1
1 import os, sys
2
2
3
3 def scan_dir(directory):
4
4 try:
5
5 for name in os.listdir(directory):
6
6 path = os.path.join(directory, name)
7
7 if os.path.isfile(path):
8
8 print(path)
9
9 if os.path.isdir(path):
10
10 scan_dir(path)
11
11 except OSError as e:
12
12 pass
13
13
14
14 scan_dir(sys.argv[1])
Dieser Code fängt die Exception ab, wenn ich das oberste Verzeichnis
nicht lesen kann. Das hat aber nichts damit zu tun, etwas in der
For-Schleife zu überspringen, sondern nur damit, die Exception an der
richtigen Stelle zu fangen, nämlich genau da, wo sie auftritt. Das
"pass" im Exceptionhandler ignoriert die Exception dann einfach.
Wenn auch dies nicht das ist, was Du haben möchtest, dann habe ich Dein
Problem noch nicht verstanden.
PS: Liebe Admin/Moderatoren, wären ein- und ausschaltbare Zeilennummern
nicht eine nette Erweiterung für Codeblöcke?
Sheeva P. schrieb:> PS: Liebe Admin/Moderatoren, wären ein- und ausschaltbare Zeilennummern> nicht eine nette Erweiterung für Codeblöcke?
Längere Codestücke soll man ja ohnehin eher als Anhang posten. Aber wenn
man es optional ein-/ausschalten kann... warum nicht.
Kannst es ja mal als Verbesserungsvorschlag posten. Dafür gibt es extra
einen eigenen Thread: Beitrag "Wunschliste & Verbesserungsvorschläge"
Sheeva Plug schrieb:
>Klar: ohne Exceptionhandling bricht der Code an der Stelle ab, wo Du ein>Listing aus einem Verzeichnis lesen willst, welches Du nicht lesen>darfst. Das ist ja auch vollkommen richtig so.
Richtig. Mein Fehler bestand darin, dass ich mich ausschließlich auf die
innere Schleife konzentriert habe und mich gewundert habe, wieso die
darin enthaltenen try/excepts mein 'Problem' mit den Leserechten nicht
abfangen konnten.
>Das wäre eher un-pythonisch. Klar kannst Du mit den Funktionen aus dem>os-Modul die Permissions abfragen, wie man das in C/C++ und den meisten>anderen Sprachen machen würde.
Hierbei war der Hintergrund der, dass mir lediglich die
Interpreter-Rückmeldung gezeigt hat, dass es ein solches Problem gibt
und ich hier ganz einfach eine Form des internen Debuggings einbaue
wollte, indem ich auf diese mögliche Eigenschaft und in der Folge auch
Fehlerursache selbst hin prüfe.
>Dieser Code fängt die Exception ab, wenn ich das oberste Verzeichnis>nicht lesen kann. Das hat aber nichts damit zu tun, etwas in der>For-Schleife zu überspringen, sondern nur damit, die Exception an der>richtigen Stelle zu fangen, nämlich genau da, wo sie auftritt. Das>"pass" im Exceptionhandler ignoriert die Exception dann einfach.
Mein Denkfehler lag darin, dass ich dass Pferd mehr oder weniger von
hinten aufgezäumt?! habe, indem ich dachte, eben jenes Problem in dem
Block abzufangen, in welchem ich die Funktion erneut aufrufe...
1
if os.path.isdir(path):
2
-----> try:
3
-----> scan_dir(path)
4
except:
5
continue
>Wenn auch dies nicht das ist, was Du haben möchtest, dann habe ich Dein>Problem noch nicht verstanden.
Doch doch, dass Problem wurde verstanden und gelöst. Vielen Dank dafür!
Ähm, kleine Verständnisfrage. Ich sehe gerade, dass Dein Code genau das
selbe macht, wie der in meinem Eingangs-Post.
Statt einer Fehlermeldung, bricht die Rekursion im Falle von
/usr/lib/ssl sauber bei private ab. Geplant war aber eigentlich, dass
das Programm dann in das nächste auflistbare Verzeichnis geht und weiter
rekursiert.
Mein usrpünglicher Gedanke war es, einmal durch den kompletten
Verzeichnisbaum zu laufen. Das ich hier /usr/lib/ssl angegeben habe, war
dem Umstand geschuldet, dass dort der 'Fehler' auftrat.
Matthias schrieb:> Ähm, kleine Verständnisfrage. Ich sehe gerade, dass Dein Code> genau das> selbe macht, wie der in meinem Eingangs-Post.>> Statt einer Fehlermeldung, bricht die Rekursion im Falle von> /usr/lib/ssl sauber bei private ab. Geplant war aber eigentlich, dass> das Programm dann in das nächste auflistbare Verzeichnis geht und weiter> rekursiert.
Also bei mir bricht die Rekursion nicht ab, sondern macht mit dem
nächsten Eintrag weiter. Wenn Du Dir eine Fehlermeldung wünschst, kannst
Du vor dem "pass" einfach ein print() einfügen, und so die Exception
(oder einen Text Deiner Wahl) ausgeben:
Sheeva P. schrieb:> Also bei mir bricht die Rekursion nicht ab, sondern macht mit dem> nächsten Eintrag weiter.
Stimmt schon. Aber dein Code macht nur weiter, wenn der Fehler in der
Rekursion auftritt. Wenn aber ein Fehler bei isfile oder isdir auftritt,
dann bricht dein Code vorzeitig ab.
tictactoe schrieb:> Sheeva P. schrieb:>> Also bei mir bricht die Rekursion nicht ab, sondern macht mit dem>> nächsten Eintrag weiter.>> Stimmt schon. Aber dein Code macht nur weiter, wenn der Fehler in der> Rekursion auftritt. Wenn aber ein Fehler bei isfile oder isdir auftritt,> dann bricht dein Code vorzeitig ab.
Wie könnten os.path.isfile() oder os.path.isdir() einen Fehler für einen
Dateinamen produzieren, der doch gerade erst mit os.listdir() von System
geholt worden ist? Parallele Zugriffe durch einen anderen Thread/Prozeß,
meinetwegen, aber sonst?
Sheeva P. schrieb:> Wie könnten os.path.isfile() oder os.path.isdir() einen Fehler für einen> Dateinamen produzieren, der doch gerade erst mit os.listdir() von System> geholt worden ist? Parallele Zugriffe durch einen anderen Thread/Prozeß,> meinetwegen, aber sonst?
Nun, das ist ja schon eine Möglichkeit. Ganz oben in der Liste der
Wahrscheinlichkeiten liegt ENOENT, weil die Datei zwischen Auslesen des
Directories und dem Zugriff mittels isfile/isdir von einem anderen
Prozess gelöscht worden ist.
tictactoe schrieb:> Sheeva P. schrieb:>> Wie könnten os.path.isfile() oder os.path.isdir() einen Fehler für einen>> Dateinamen produzieren, der doch gerade erst mit os.listdir() von System>> geholt worden ist? Parallele Zugriffe durch einen anderen Thread/Prozeß,>> meinetwegen, aber sonst?>> Nun, das ist ja schon eine Möglichkeit. Ganz oben in der Liste der> Wahrscheinlichkeiten liegt ENOENT, weil die Datei zwischen Auslesen des> Directories und dem Zugriff mittels isfile/isdir von einem anderen> Prozess gelöscht worden ist.
Entschuldige, aber ENOENT (sowie ggf. ENOPERM) ist die von mir
erwähnte Möglichkeit des parallelen Zugriffs durch einen anderen
Thread/Prozeß. Mir fallen ansonsten nur sehr merkwürdige Fehler im
Dateisystem (zum Beispiel eine fehlerhafte FUSE-Implementierung) ein.
Aber hier ging es ja nicht um konkurrierende Schreibzugriffe, sondern um
ein konkretes Problem in einem konkreten Code, und bis zum Beweis des
Gegenteils glaube ich, das Problem des OP gelöst und zu seiner
Erleuchtung beigetragen zu haben. Mir war dabei leider nicht klar, daß
ich angelegentlich auch noch alle anderen potentiell möglichen, äußerst
unwahrscheinlichen Probleme der Welt, der Galaxie und des Universums
hätte lösen sollen. ;-)
Sheeva Plug schrieb:
>und bis zum Beweis des Gegenteils glaube ich, das Problem des OP gelöst und zu >seiner Erleuchtung beigetragen zu haben.
Als Beweis und Fürsprache meinerseits, könnte ich eine File meiner
Standardausgabe hier anfügen, welche als Inhalt eine gänzlich rekursiv
durchlaufene /dev/sda1, samt den hierauf befindlichen Dateien,
Verzeichnissen, Links und entstandenen Fehlermeldungen abbildet.
Ich habe aber keinen an der Glocke, daher gebe ich der Gemeinschaft mein
Ehrenwort, dass der sich im Laufe dieses Threads entwickelte Code mein
Problem gelöst und zu der eingangs beschriebenen Magie geführt hat.
Weitere Fragestellungen waren nicht Gegenstand dieses Threads, aber
aufgrund eines potentiell erwartbaren Popcornfaktors warne ich davor,
diesen Thread als gelöst anzusehen.
Mal sehen, wohin uns das Ganze noch so führt. Ring frei!