Möchten Sie versuchen, eine Datei zu löschen, wenn sie vorhanden ist (und fehlschlagen, wenn Sie keine Berechtigungen haben), oder nach besten Kräften löschen, ohne dass Ihnen ein Fehler ins Gesicht zurückgeworfen wird?
Donal Fellows
Ich wollte "das erstere" von dem machen, was @DonalFellows sagte. Dafür wäre Scotts Originalcode wohl ein guter Ansatz?
LarsH
Erstellen Sie eine aufgerufene Funktion unlinkund fügen Sie sie in den Namespace PHP ein.
Lama12345
1
@LarsH Siehe den zweiten Codeblock der akzeptierten Antwort. Die Ausnahme wird erneut ausgelöst, wenn die Ausnahme alles andere als ein Fehler "Keine solche Datei oder kein solches Verzeichnis" ist.
jpmc26
Antworten:
613
Ein pythonischerer Weg wäre:
try:
os.remove(filename)exceptOSError:pass
Dies dauert zwar noch mehr Zeilen und sieht sehr hässlich aus, vermeidet jedoch den unnötigen Aufruf os.path.exists()und folgt der Python-Konvention der übermäßigen Verwendung von Ausnahmen.
Es kann sich lohnen, eine Funktion zu schreiben, um dies für Sie zu tun:
import os, errno
def silentremove(filename):try:
os.remove(filename)exceptOSErroras e:# this would be "except OSError, e:" before Python 2.6if e.errno != errno.ENOENT:# errno.ENOENT = no such file or directoryraise# re-raise exception if a different error occurred
Aber würde dies passieren, wenn der Entfernungsvorgang fehlschlägt (schreibgeschütztes Dateisystem oder ein anderes unerwartetes Problem)?
Scott C Wilson
134
Die Tatsache, dass die Datei bei der os.path.exists()Ausführung vorhanden ist, bedeutet nicht, dass sie bei der os.remove()Ausführung vorhanden ist.
Kindall
8
Meine +1, aber übermäßige Verwendung von Ausnahmen ist keine Python-Konvention :) Oder doch?
Pepr
8
@pepr Ich habe nur humorvoll kritisiert, wie Ausnahmen Teil des normalen Verhaltens in Python sind. Zum Beispiel Iteratoren müssen Ausnahmen erhöhen , um das Iterieren zu stoppen.
Matt
5
+1 weil ich nicht +2 kann. Abgesehen davon, dass es mehr pythonisch ist, ist dieses tatsächlich korrekt, während das Original aus dem vorgeschlagenen Grund nicht korrekt ist. Solche Rennbedingungen führen zu Sicherheitslücken, schwer zu
reproduzierenden
159
Ich ziehe es vor, eine Ausnahme zu unterdrücken, anstatt nach der Existenz der Datei zu suchen , um einen TOCTTOU- Fehler zu vermeiden . Matts Antwort ist ein gutes Beispiel dafür, aber wir können sie unter Python 3 leicht vereinfachen, indem wir contextlib.suppress():
import contextlib
with contextlib.suppress(FileNotFoundError):
os.remove(filename)
Wenn filenamees sich um ein pathlib.PathObjekt anstelle eines Strings handelt, können wir dessen .unlink()Methode anstelle von verwenden os.remove(). Nach meiner Erfahrung sind Pfadobjekte für die Manipulation des Dateisystems nützlicher als Zeichenfolgen.
Da alles in dieser Antwort exklusiv für Python 3 ist, bietet es einen weiteren Grund für ein Upgrade.
Dies ist der pythonischste Weg wie im Dezember 2015. Python entwickelt sich jedoch weiter.
Mayank Jaiswal
2
Ich habe keine remove () -Methode für pathlib.Path-Objekte in Python 3.6 gefunden
BrianHVB
1
@ Jeffbyrnes: Ich würde das eine Verletzung des Zen von Python nennen: "Es sollte einen - und vorzugsweise nur einen - offensichtlichen Weg geben, dies zu tun." Wenn Sie zwei Methoden hätten, die dasselbe taten, würden Sie eine Mischung davon im laufenden Quellcode erhalten, was für den Leser schwieriger zu befolgen wäre. Ich vermute, sie wollten Konsistenz mit unlink(2), was bei weitem die älteste relevante Schnittstelle hier ist.
Kevin
1
@nivk: Wenn Sie eine exceptKlausel benötigen , sollten Sie try/ verwenden except. Es kann nicht sinnvoll gekürzt werden, da Sie eine Zeile zum Einführen des ersten Blocks, den Block selbst, eine Zeile zum Einführen des zweiten Blocks und dann diesen Block haben müssen, damit try/ exceptbereits so knapp wie möglich ist.
Kevin
1
Es ist erwähnenswert, dass diese Lösung im Gegensatz zu einem Try / Except-Block bedeutet, dass Sie nicht herumspielen müssen, um eine Ausnahme zu erstellen, um sicherzustellen, dass die Messwerte für die Testabdeckung relevant sind.
Park
50
os.path.existsGibt sowohl Truefür Ordner als auch für Dateien zurück. Verwenden Sie os.path.isfile, um zu überprüfen, ob die Datei stattdessen vorhanden ist.
Jedes Mal, wenn wir auf Existenz testen und dann basierend auf diesem Test entfernen, öffnen wir uns einer Rennbedingung. (Was ist, wenn die Datei dazwischen verschwindet?)
Alex L
34
Wie wäre es mit einer authentischen ternären Operation im Geiste von Andy Jones 'Antwort:
@BrianHVB Da Ternaries dazu dienen, basierend auf einer Bedingung zwischen zwei Werten zu wählen, keine Verzweigung durchzuführen.
Bgusach
1
Ich verwende keine Ausnahmen für die Flusskontrolle. Sie erschweren das Verständnis des Codes und können vor allem einen anderen Fehler maskieren (z. B. ein Berechtigungsproblem, das das Löschen einer Datei blockiert), das zu einem stillen Fehler führt.
Ed King
11
Das ist nicht atomar. Die Datei kann zwischen Aufrufen gelöscht und entfernt werden. Es ist sicherer, den Vorgang zu versuchen und ihn fehlschlagen zu lassen.
ConnorWGarvey
1
@ nam-g-vu Nur zu Ihrer Information, ich habe Ihre Bearbeitung zurückgesetzt, weil Sie im Grunde nur die Syntax des ursprünglichen Fragestellers als Alternative hinzugefügt haben. Da sie nach etwas anderem gesucht haben, glaube ich nicht, dass die Bearbeitung für diese spezielle Antwort von Bedeutung ist.
Tim Keating
9
Eine andere Möglichkeit, festzustellen, ob die Datei (oder Dateien) vorhanden ist, und sie zu entfernen, ist die Verwendung des Modulglob.
from glob import glob
import os
for filename in glob("*.csv"):
os.remove(filename)
Glob findet alle Dateien, die das Muster mit einem * nix-Platzhalter auswählen könnten, und durchläuft die Liste.
Viele von Ihnen mögen anderer Meinung sein - möglicherweise aus Gründen wie der Betrachtung der vorgeschlagenen Verwendung von Ternären als "hässlich" -, aber dies wirft die Frage auf, ob wir Menschen zuhören sollten, die an hässliche Standards gewöhnt sind, wenn sie etwas Nicht-Standard "hässlich" nennen.
Das ist sauber - ich verwende keine Ausnahmen für die Flusskontrolle. Sie erschweren das Verständnis des Codes und können vor allem einen anderen Fehler maskieren (z. B. ein Berechtigungsproblem, das das Löschen einer Datei blockiert), das zu einem stillen Fehler führt.
Ed King
2
Es ist nicht schön, weil davon ausgegangen wird, dass es nur einen Prozess gibt, der den Dateinamen ändert. Es ist nicht atomar. Es ist sicher und korrekt, den Vorgang zu versuchen und ordnungsgemäß fehlzuschlagen. Es ist ärgerlich, dass Python nicht standardisieren kann. Wenn wir ein Verzeichnis hätten, würden wir shutil verwenden und es würde genau das unterstützen, was wir wollen.
ConnorWGarvey
2
In Python 3.4 oder einer höheren Version wäre der pythonische Weg:
import os
from contextlib import suppress
with suppress(OSError):
os.remove(filename)
Etwas wie das? Nutzt die Kurzschlussauswertung. Wenn die Datei nicht vorhanden ist, kann die gesamte Bedingung nicht wahr sein, sodass Python den zweiten Teil nicht auswertet.
Dies ist definitiv nicht "pythonischer" - tatsächlich warnt Guido speziell davor und bezeichnet dies als "Missbrauch" der booleschen Operatoren.
Abarnert
1
Oh, ich stimme zu - ein Teil der Frage wurde nach einem einzeiligen Weg gestellt und dies war das erste, was mir in den Sinn kam
Andy Jones
4
Nun, Sie könnten es auch zu einem Einzeiler machen, indem Sie einfach die neue Zeile nach dem Doppelpunkt entfernen ... Oder, noch besser, Guide fügte widerwillig den if-Ausdruck hinzu, um die Leute davon abzuhalten, "die booleschen Operatoren zu missbrauchen", und es gibt eine großartige Gelegenheit, dies zu beweisen dass alles missbraucht werden kann: os.remove ("gogogo.php") wenn os.path.exists ("gogogo.php") sonst keine. :)
Wenn Sie eine ganze Funktion schreiben müssen, verfehlt dies den Punkt der Einzeiler
Ion Lesan
@Ion Lesan Das OP ist der "beste" Weg, um dieses Problem zu lösen. Ein Einzeiler ist niemals ein besserer Weg, wenn er die Lesbarkeit gefährdet.
Baz
Angesichts der inhärent weit gefassten Definition von "am besten" werde ich nicht in diesem Sinne argumentieren, obwohl dies eindeutig von TOCTOU beeinflusst wird. Und definitiv keine KISS-Lösung.
Ion Lesan
@Matt Stimmt, aber leiden nicht einige der hier angebotenen Lösungen unter diesem Problem?
Baz
0
Dies ist eine andere Lösung:
if os.path.isfile(os.path.join(path, filename)):
os.remove(os.path.join(path, filename))
Ich habe verwendet rm, um zu erzwingen, nicht vorhandene Dateien mit --preserve-rootals Option zu löschen rm.
--preserve-root
donot remove `/' (default)
rm --help | grep "force"-f,--force ignore nonexistent files and arguments, never prompt
Wir können auch safe-rm ( sudo apt-get install safe-rm) verwenden
Safe-rm ist ein Sicherheitstool, das das versehentliche Löschen wichtiger Dateien verhindern soll, indem / bin / rm durch einen Wrapper ersetzt wird, der die angegebenen Argumente mit einer konfigurierbaren schwarzen Liste von Dateien und Verzeichnissen vergleicht, die niemals entfernt werden sollten.
Zuerst überprüfe ich, ob Ordner- / Dateipfad vorhanden ist oder nicht. Dadurch wird verhindert, dass die Variable fileToRemove /folderToRemove to the string-r / `festgelegt wird.
Die Verwendung einer Shell für etwas, das so trivial ist, ist übertrieben und dieser Ansatz funktioniert auch nicht plattformübergreifend (z. B. Windows).
Nabla
4
Die Verwendung einer Shell anstelle der Standardbibliothek (z. B. os.remove) ist immer eine der am wenigsten pythonischen / sauberen Methoden, um etwas zu tun. Beispielsweise müssen Sie von der Shell zurückgegebene Fehler manuell behandeln.
Nabla
1
Ich habe meine Antwort hinzugefügt, um sie rmsicher zu verwenden und zu verhindern rm -r /. @ JonBrave
Alper
1
rm -f --preserve-rootist nicht gut genug ( --preserve-rootist wahrscheinlich sowieso die Standardeinstellung). Ich gab -r /als Beispiel , was ist, wenn es -r /homeoder was auch immer? Sie wollen wahrscheinlich rm -f -- $fileToRemove, aber das ist nicht der Punkt.
JonBrave
3
Nicht so, wie Sie es verwendet haben, mit einem Variablennamen (Umgebungsvariable) und ohne Anführungszeichen und ohne Schutz, nein. Und nicht für diese Frage, nein. Es os.system('rm ...')ist äußerst gefährlich, Unachtsame auszusetzen.
unlink
und fügen Sie sie in den Namespace PHP ein.Antworten:
Ein pythonischerer Weg wäre:
Dies dauert zwar noch mehr Zeilen und sieht sehr hässlich aus, vermeidet jedoch den unnötigen Aufruf
os.path.exists()
und folgt der Python-Konvention der übermäßigen Verwendung von Ausnahmen.Es kann sich lohnen, eine Funktion zu schreiben, um dies für Sie zu tun:
quelle
os.path.exists()
Ausführung vorhanden ist, bedeutet nicht, dass sie bei deros.remove()
Ausführung vorhanden ist.Ich ziehe es vor, eine Ausnahme zu unterdrücken, anstatt nach der Existenz der Datei zu suchen , um einen TOCTTOU- Fehler zu vermeiden . Matts Antwort ist ein gutes Beispiel dafür, aber wir können sie unter Python 3 leicht vereinfachen, indem wir
contextlib.suppress()
:Wenn
filename
es sich um einpathlib.Path
Objekt anstelle eines Strings handelt, können wir dessen.unlink()
Methode anstelle von verwendenos.remove()
. Nach meiner Erfahrung sind Pfadobjekte für die Manipulation des Dateisystems nützlicher als Zeichenfolgen.Da alles in dieser Antwort exklusiv für Python 3 ist, bietet es einen weiteren Grund für ein Upgrade.
quelle
unlink(2)
, was bei weitem die älteste relevante Schnittstelle hier ist.except
Klausel benötigen , sollten Sietry
/ verwendenexcept
. Es kann nicht sinnvoll gekürzt werden, da Sie eine Zeile zum Einführen des ersten Blocks, den Block selbst, eine Zeile zum Einführen des zweiten Blocks und dann diesen Block haben müssen, damittry
/except
bereits so knapp wie möglich ist.os.path.exists
Gibt sowohlTrue
für Ordner als auch für Dateien zurück. Verwenden Sieos.path.isfile
, um zu überprüfen, ob die Datei stattdessen vorhanden ist.quelle
Wie wäre es mit einer authentischen ternären Operation im Geiste von Andy Jones 'Antwort:
quelle
Eine andere Möglichkeit, festzustellen, ob die Datei (oder Dateien) vorhanden ist, und sie zu entfernen, ist die Verwendung des Modulglob.
Glob findet alle Dateien, die das Muster mit einem * nix-Platzhalter auswählen könnten, und durchläuft die Liste.
quelle
Verwenden Sie ab Python 3.8
missing_ok=True
undpathlib.Path.unlink
( Dokumente hier )quelle
Matts Antwort ist die richtige für ältere Pythons und Kevins die richtige Antwort für neuere.
Wenn Sie die Funktion nicht kopieren möchten
silentremove
, wird diese Funktionalität in path.py als remove_p angezeigt :quelle
ist ein Einzeiler.
Viele von Ihnen mögen anderer Meinung sein - möglicherweise aus Gründen wie der Betrachtung der vorgeschlagenen Verwendung von Ternären als "hässlich" -, aber dies wirft die Frage auf, ob wir Menschen zuhören sollten, die an hässliche Standards gewöhnt sind, wenn sie etwas Nicht-Standard "hässlich" nennen.
quelle
In Python 3.4 oder einer höheren Version wäre der pythonische Weg:
quelle
Etwas wie das? Nutzt die Kurzschlussauswertung. Wenn die Datei nicht vorhanden ist, kann die gesamte Bedingung nicht wahr sein, sodass Python den zweiten Teil nicht auswertet.
quelle
Ein KISS-Angebot:
Und dann:
quelle
Dies ist eine andere Lösung:
quelle
Eine andere Lösung mit Ihrer eigenen Nachricht in Ausnahme.
quelle
Ich habe verwendet
rm
, um zu erzwingen, nicht vorhandene Dateien mit--preserve-root
als Option zu löschenrm
.Wir können auch safe-rm (
sudo apt-get install safe-rm
) verwendenZuerst überprüfe ich, ob Ordner- / Dateipfad vorhanden ist oder nicht. Dadurch wird verhindert, dass die Variable fileToRemove
/
folderToRemoveto the string
-r / `festgelegt wird.quelle
rm
sicher zu verwenden und zu verhindernrm -r /
. @ JonBraverm -f --preserve-root
ist nicht gut genug (--preserve-root
ist wahrscheinlich sowieso die Standardeinstellung). Ich gab-r /
als Beispiel , was ist, wenn es-r /home
oder was auch immer? Sie wollen wahrscheinlichrm -f -- $fileToRemove
, aber das ist nicht der Punkt.os.system('rm ...')
ist äußerst gefährlich, Unachtsame auszusetzen.