Voulez-vous essayer de supprimer un fichier s'il existe (et échouer si vous manquez d'autorisations) ou faire une suppression au mieux et ne jamais avoir une erreur renvoyée en face?
Donal Fellows
Je voulais faire "l'ancien" de ce que @DonalFellows a dit. Pour cela, je suppose que le code original de Scott serait une bonne approche?
LarsH
Créez une fonction appelée unlinket placez-la dans l'espace de noms PHP.
lama12345
1
@LarsH Voir le deuxième bloc de code de la réponse acceptée. Il relance l'exception si l'exception est tout sauf une erreur «aucun fichier ou répertoire».
jpmc26
Réponses:
613
Une manière plus pythonique serait:
try:
os.remove(filename)exceptOSError:pass
Bien que cela prenne encore plus de lignes et semble très moche, cela évite l'appel inutile os.path.exists()et suit la convention python de surutilisation des exceptions.
Il peut être utile d'écrire une fonction pour ce faire:
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
Mais cela se passerait-il si l'opération de suppression échouait (système de fichiers en lecture seule ou autre problème inattendu)?
Scott C Wilson
136
De plus, le fait que le fichier existe lorsqu'il os.path.exists()est exécuté ne signifie pas qu'il existe lorsqu'il os.remove()est exécuté.
2012
8
Mon +1, mais la surutilisation des exceptions n'est pas une convention Python :) Ou est-ce?
pepr
8
@pepr Je critiquais avec humour la façon dont les exceptions font partie du comportement normal en python. Par exemple, les itérateurs doivent lever des exceptions pour arrêter l'itération.
Matt
5
+1 parce que je ne peux pas +2. En plus d'être plus Pythonic, celui-ci est en fait correct, tandis que l'original ne l'est pas, pour la raison que tout le monde suggère. De telles conditions de course mènent à des failles de sécurité, des bugs difficiles à reproduire, etc.
abarnert
160
Je préfère supprimer une exception plutôt que de vérifier l'existence du fichier, pour éviter un bug TOCTTOU . La réponse de Matt en est un bon exemple, mais nous pouvons la simplifier légèrement sous Python 3, en utilisant contextlib.suppress():
import contextlib
with contextlib.suppress(FileNotFoundError):
os.remove(filename)
Si filename est un pathlib.Pathobjet au lieu d'une chaîne, nous pouvons appeler sa .unlink()méthode au lieu d'utiliser os.remove(). D'après mon expérience, les objets Path sont plus utiles que les chaînes pour la manipulation du système de fichiers.
Étant donné que tout dans cette réponse est exclusif à Python 3, il fournit une autre raison de mettre à niveau.
C'est la manière la plus pythonique de décembre 2015. Python continue cependant d'évoluer.
Mayank Jaiswal
2
Je n'ai trouvé aucune méthode remove () pour les objets pathlib.Path sur Python 3.6
BrianHVB
1
@jeffbyrnes: J'appellerais cela une violation du Zen de Python: "Il devrait y avoir une - et de préférence une seule - manière évidente de le faire." Si vous aviez deux méthodes qui faisaient la même chose, vous vous retrouveriez avec un mélange d'entre elles dans l'exécution du code source, ce qui serait plus difficile à suivre pour le lecteur. Je soupçonne qu'ils voulaient une cohérence avec unlink(2), qui est de loin la plus ancienne interface pertinente ici.
Kevin
1
@nivk: Si vous avez besoin d'une exceptclause, vous devez utiliser try/ except. Il ne peut pas être raccourci de manière significative, car vous devez avoir une ligne pour introduire le premier bloc, le bloc lui-même, une ligne pour introduire le deuxième bloc, puis ce bloc, donc try/ exceptest déjà aussi concis que possible.
Kevin
1
Il convient de noter que contrairement à un bloc try / except, cette solution signifie que vous n'avez pas à vous soucier de créer une exception afin de vous assurer que les mesures de couverture de test sont pertinentes.
thclark
50
os.path.existsrenvoie Truepour les dossiers ainsi que les fichiers. Pensez à utiliser os.path.isfilepour vérifier si le fichier existe à la place.
Chaque fois que nous testons l'existence et retirons ensuite sur la base de ce test, nous nous ouvrons à une condition de concurrence. (Et si le fichier disparaît entre les deux?)
Alex L
34
Dans l'esprit de la réponse d'Andy Jones, que diriez-vous d'une authentique opération ternaire:
@BrianHVB Parce que les ternaires sont là pour choisir entre deux valeurs basées sur une condition, pas pour faire des branchements.
bgusach
1
Je n'aime pas utiliser d'exceptions pour le contrôle de flux. Ils rendent le code difficile à comprendre et, plus important encore, peuvent masquer une autre erreur se produisant (comme un problème d'autorisation bloquant la suppression d'un fichier) qui provoquera un échec silencieux.
Ed King
11
Ce n'est pas atomique. Le fichier peut être supprimé entre les appels à existe et supprimer. Il est plus sûr de tenter l'opération et de lui permettre d'échouer.
ConnorWGarvey
1
@ nam-g-vu Juste pour info, j'ai annulé votre modification parce que vous venez d'ajouter la syntaxe du questionneur d'origine comme alternative. Comme ils cherchaient quelque chose de différent, je ne pense pas que la modification soit pertinente pour cette réponse particulière.
Tim Keating
10
Depuis Python 3.8, utilisez missing_ok=Trueet pathlib.Path.unlink( docs ici )
from pathlib importPath
my_file =Path("./dir1/dir2/file.txt")# Python 3.8+
my_file.unlink(missing_ok=True)# Python 3.7 and earlierif my_file.exists():
my_file.unlink()
Beaucoup d'entre vous ne sont peut-être pas d'accord - peut-être pour des raisons telles que le fait de considérer l'utilisation proposée des ternaires comme "laide" - mais cela soulève la question de savoir si nous devons écouter les gens habitués à des normes moches lorsqu'ils appellent quelque chose de non standard "laid".
c'est propre - je n'aime pas utiliser d'exceptions pour le contrôle de flux. Ils rendent le code difficile à comprendre et, plus important encore, peuvent masquer une autre erreur se produisant (comme un problème d'autorisation bloquant la suppression d'un fichier) qui provoquera un échec silencieux.
Ed King
2
Ce n'est pas joli car cela suppose qu'il n'y a qu'un seul processus qui modifiera le nom de fichier. Ce n'est pas atomique. Il est sûr et correct de tenter l'opération et d'échouer avec élégance. C'est ennuyeux que Python ne puisse pas standardiser. Si nous avions un répertoire, nous utiliserions shutil et il prendrait en charge exactement ce que nous voulons.
ConnorWGarvey
2
Dans Python 3.4 ou version ultérieure, la méthode pythonique serait:
import os
from contextlib import suppress
with suppress(OSError):
os.remove(filename)
Quelque chose comme ça? Profite de l'évaluation des courts-circuits. Si le fichier n'existe pas, le conditionnel entier ne peut pas être vrai, donc python ne dérangera pas l'évaluation de la deuxième partie.
Ce n'est certainement pas "plus Pythonique" - en fait, c'est quelque chose que Guido met en garde spécifiquement, et se réfère à "l'abus" des opérateurs booléens.
abarnert
1
oh, je suis d'accord - une partie de la question demandait un chemin d'une ligne et c'était la première chose qui m'est venue à l'esprit
Andy Jones
4
Eh bien, vous pouvez également en faire une ligne simple en supprimant simplement la nouvelle ligne après les deux points ... Ou, mieux encore, Guide a ajouté à contrecœur l'expression si pour empêcher les gens "d'abuser des opérateurs booléens", et il y a une excellente occasion de prouver que tout peut être utilisé abusivement: os.remove ("gogogo.php") si os.path.exists ("gogogo.php") else Aucun. :)
Si vous devez écrire une fonction entière, il manque en quelque sorte le but des lignes
simples
@Ion Lesan L'OP est la "meilleure" façon de résoudre ce problème. Un liner n'est jamais un meilleur moyen s'il met en péril la lisibilité.
Baz
Compte tenu de la définition intrinsèquement large de «meilleur», je ne vais pas discuter dans ce sens, bien qu'il soit clairement affecté par TOCTOU. Et certainement pas une solution KISS.
Ion Lesan
@Matt True, mais un certain nombre de solutions proposées ici ne souffrent pas de ce problème?
Baz
0
Voici une autre solution:
if os.path.isfile(os.path.join(path, filename)):
os.remove(os.path.join(path, filename))
J'ai utilisé rmce qui peut forcer la suppression de fichiers inexistants avec --preserve-rootcomme option pour rm.
--preserve-root
donot remove `/' (default)
rm --help | grep "force"-f,--force ignore nonexistent files and arguments, never prompt
Nous pouvons également utiliser safe-rm ( sudo apt-get install safe-rm)
Safe-rm est un outil de sécurité destiné à empêcher la suppression accidentelle de fichiers importants en remplaçant / bin / rm par un wrapper, qui vérifie les arguments donnés par rapport à une liste noire configurable de fichiers et de répertoires qui ne doivent jamais être supprimés.
Je vérifie d'abord si le chemin du dossier / fichier existe ou non. Cela empêchera de définir la variable fileToRemove /folderToRemove to the string-r / `.
Utiliser un shell pour quelque chose d'aussi banal est exagéré et cette approche ne fonctionnera pas non plus multiplateforme (c'est-à-dire Windows).
Nabla
4
Utiliser un shell au lieu de la bibliothèque standard (os.remove par exemple) est toujours l'une des façons les moins pythoniques / propres de faire quelque chose. Par exemple, vous devez gérer manuellement les erreurs renvoyées par le shell.
Nabla
1
J'ai ajouté ma réponse pour utiliser en rmtoute sécurité et prévenir rm -r /. @JonBrave
alper
1
rm -f --preserve-rootn'est pas assez bon ( --preserve-rootc'est probablement la valeur par défaut de toute façon). J'ai donné -r /comme exemple , que faire si c'est -r /homeou quoi? Vous voulez probablement rm -f -- $fileToRemove, mais ce n'est pas le but.
JonBrave
3
Pas comme vous l'avez utilisé, avec un nom de variable (variable d'environnement), sans guillemets et sans protection, non. Et pas pour cette question, non. Exposer les imprudents os.system('rm ...')est extrêmement dangereux, désolé.
unlink
et placez-la dans l'espace de noms PHP.Réponses:
Une manière plus pythonique serait:
Bien que cela prenne encore plus de lignes et semble très moche, cela évite l'appel inutile
os.path.exists()
et suit la convention python de surutilisation des exceptions.Il peut être utile d'écrire une fonction pour ce faire:
la source
os.path.exists()
est exécuté ne signifie pas qu'il existe lorsqu'ilos.remove()
est exécuté.Je préfère supprimer une exception plutôt que de vérifier l'existence du fichier, pour éviter un bug TOCTTOU . La réponse de Matt en est un bon exemple, mais nous pouvons la simplifier légèrement sous Python 3, en utilisant
contextlib.suppress()
:Si
filename
est unpathlib.Path
objet au lieu d'une chaîne, nous pouvons appeler sa.unlink()
méthode au lieu d'utiliseros.remove()
. D'après mon expérience, les objets Path sont plus utiles que les chaînes pour la manipulation du système de fichiers.Étant donné que tout dans cette réponse est exclusif à Python 3, il fournit une autre raison de mettre à niveau.
la source
unlink(2)
, qui est de loin la plus ancienne interface pertinente ici.except
clause, vous devez utilisertry
/except
. Il ne peut pas être raccourci de manière significative, car vous devez avoir une ligne pour introduire le premier bloc, le bloc lui-même, une ligne pour introduire le deuxième bloc, puis ce bloc, donctry
/except
est déjà aussi concis que possible.os.path.exists
renvoieTrue
pour les dossiers ainsi que les fichiers. Pensez à utiliseros.path.isfile
pour vérifier si le fichier existe à la place.la source
Dans l'esprit de la réponse d'Andy Jones, que diriez-vous d'une authentique opération ternaire:
la source
Depuis Python 3.8, utilisez
missing_ok=True
etpathlib.Path.unlink
( docs ici )la source
Une autre façon de savoir si le fichier (ou les fichiers) existe et de le supprimer est d'utiliser le module glob.
Glob trouve tous les fichiers qui pourraient sélectionner le modèle avec un caractère générique * nix et boucle la liste.
la source
La réponse de Matt est la bonne pour les anciens Pythons et Kevin pour les plus récents.
Si vous ne souhaitez pas copier la fonction pour
silentremove
, cette fonctionnalité est exposée dans path.py en tant que remove_p :la source
est une doublure.
Beaucoup d'entre vous ne sont peut-être pas d'accord - peut-être pour des raisons telles que le fait de considérer l'utilisation proposée des ternaires comme "laide" - mais cela soulève la question de savoir si nous devons écouter les gens habitués à des normes moches lorsqu'ils appellent quelque chose de non standard "laid".
la source
Dans Python 3.4 ou version ultérieure, la méthode pythonique serait:
la source
Quelque chose comme ça? Profite de l'évaluation des courts-circuits. Si le fichier n'existe pas, le conditionnel entier ne peut pas être vrai, donc python ne dérangera pas l'évaluation de la deuxième partie.
la source
Une offre KISS:
Et alors:
la source
Voici une autre solution:
la source
Une autre solution avec votre propre message en exception.
la source
J'ai utilisé
rm
ce qui peut forcer la suppression de fichiers inexistants avec--preserve-root
comme option pourrm
.Nous pouvons également utiliser safe-rm (
sudo apt-get install safe-rm
)Je vérifie d'abord si le chemin du dossier / fichier existe ou non. Cela empêchera de définir la variable fileToRemove
/
folderToRemoveto the string
-r / `.la source
rm
toute sécurité et prévenirrm -r /
. @JonBraverm -f --preserve-root
n'est pas assez bon (--preserve-root
c'est probablement la valeur par défaut de toute façon). J'ai donné-r /
comme exemple , que faire si c'est-r /home
ou quoi? Vous voulez probablementrm -f -- $fileToRemove
, mais ce n'est pas le but.os.system('rm ...')
est extrêmement dangereux, désolé.