Wie entferne / lösche ich einen Ordner, der nicht leer ist?

847

Beim Versuch, einen nicht leeren Ordner zu löschen, wird der Fehler "Zugriff verweigert" angezeigt. Ich habe bei meinem Versuch den folgenden Befehl verwendet : os.remove("/folder_name").

Was ist der effektivste Weg, um einen Ordner / ein Verzeichnis zu entfernen / löschen, der nicht leer ist?

Amara
quelle
32
Beachten Sie auch, dass os.remove auch dann fehlschlagen würde, wenn das Verzeichnis leer wäre, da die richtige Funktion os.rmdir ist.
Zot
Und für spezifisches rm -rfVerhalten siehe: stackoverflow.com/questions/814167/…
Ciro Santilli 法轮功 病毒 审查 六四 事件 法轮功

Antworten:

1348
import shutil

shutil.rmtree('/folder_name')

Standardbibliotheksreferenz: shutil.rmtree .

Schlägt rmtreestandardmäßig in Ordnerbäumen fehl, die schreibgeschützte Dateien enthalten. Wenn Sie möchten, dass der Ordner gelöscht wird, unabhängig davon, ob er schreibgeschützte Dateien enthält, verwenden Sie

shutil.rmtree('/folder_name', ignore_errors=True)
ddaa
quelle
73
Beachten Sie, dass dies rmtreefehlschlagen wird, wenn schreibgeschützte Dateien vorhanden sind: stackoverflow.com/questions/2656322/…
Sridhar Ratnakumar
9
Dies funktioniert bei mir nicht: Traceback (letzter Aufruf zuletzt): Datei "foo.py", Zeile 31, in <module> shutil.rmtree (thistestdir) Datei "/usr/lib/python2.6/shutil.py ", Zeile 225, in rmtree onerror (os.rmdir, Pfad, sys.exc_info ()) Datei" /usr/lib/python2.6/shutil.py ", Zeile 223, in rmtree os.rmdir (Pfad) OSError: [Errno 90] Verzeichnis nicht leer: '/ path / to / rmtree'
Clayton Hughes
4
Clayton: Höchstwahrscheinlich wurde eine Datei gleichzeitig hinzugefügt, während rmtree damit beschäftigt war, Dinge zu löschen. "Rm -rf" würde genauso fehlschlagen.
Ddaa
13
Weiß jemand, warum diese Funktionalität nicht im Betriebssystempaket enthalten ist? Scheint, als ob os.rmdir ziemlich nutzlos ist. Irgendwelche guten Argumente dafür, warum es so implementiert wird?
Malcolm
21
@Malcolm Das Paket ist ein Wrapper für Betriebssystemfunktionen. Auf POSIX- Systemen schlägt rmdir fehl, wenn das Verzeichnis nicht leer ist. Ubuntu und Windows sind in dieser Hinsicht beliebte Beispiele für POSIX-Konformität.
Iain Samuel McLean Elder
138

Von dem Python - docs auf os.walk():

# Delete everything reachable from the directory named in 'top',
# assuming there are no symbolic links.
# CAUTION:  This is dangerous!  For example, if top == '/', it
# could delete all your disk files.
import os
for root, dirs, files in os.walk(top, topdown=False):
    for name in files:
        os.remove(os.path.join(root, name))
    for name in dirs:
        os.rmdir(os.path.join(root, name))
kkubasik
quelle
1
Nun, vielleicht irre ich mich beim Downmodding. Aber ich kann, im Moment denke ich, dass es richtig ist.
Ddaa
3
@ddaa: Während die Verwendung von Shutil definitiv der einfachste Weg ist, ist an dieser Lösung sicherlich nichts Unpythonisches. Ich hätte diese Antwort nicht positiv bewertet, aber ich habe diesmal nur Zeit, um Ihre Ablehnung abzubrechen :)
Jeremy Cantrell
7
Der Code selbst ist pythonisch. Die Verwendung anstelle von shutil.rmtree in einem echten Programm wäre unpythonisch: Das würde die "eine offensichtliche Art, dies zu tun" ignorieren. Wie auch immer, das ist Semantik, die den Downmod entfernt.
Ddaa
2
@ddaa Ist es unpythonisch, jede gelöschte Datei oder jedes gelöschte Verzeichnis protokollieren zu wollen? Ich bin nicht sicher, wie ich das mit shutil.rmtree machen soll.
Jonathan Komar
4
@ddaa Es war Denkanstoß, dh Rhetorik. Ich weiß was ich tue. Ich dachte nur, Sie möchten vielleicht "die offensichtliche Vorgehensweise" überdenken, indem Sie einen Grund angeben, warum shutil.rmtree möglicherweise nicht die richtige "Passform" ist.
Jonathan Komar
112
import shutil
shutil.rmtree(dest, ignore_errors=True)
Siva Mandadi
quelle
1
Dies ist die richtige Antwort. Obwohl ich in meinem System alles in dem bestimmten Ordner auf Schreiben und Lesen eingestellt habe, wird beim Löschen eine Fehlermeldung angezeigt. ignore_errors=Truelöst das Problem.
Aventinus
3
In meiner Antwort wird der onerrorParameter anstelle von verwendet ignore_errors. Auf diese Weise werden schreibgeschützte Dateien gelöscht und nicht ignoriert.
Dave Chandler
Ja, dies löscht bei einem Fehler keine Dateien. Grundsätzlich wird also die gesamte rmtree()Methode ignoriert.
Juha Untinen
1
Dies sollte eine kleine Änderung der 6 Jahre zuvor akzeptierten Antwort gewesen sein, eher eine neue Antwort. Ich mache das jetzt.
Jean-François Corbett
22

Ab Python 3.4 können Sie Folgendes verwenden:

import pathlib

def delete_folder(pth) :
    for sub in pth.iterdir() :
        if sub.is_dir() :
            delete_folder(sub)
        else :
            sub.unlink()
    pth.rmdir() # if you just want to delete dir content, remove this line

Wo pthist eine pathlib.PathInstanz? Schön, aber vielleicht nicht der schnellste.

Yota
quelle
10

Von docs.python.org :

Dieses Beispiel zeigt, wie Sie einen Verzeichnisbaum unter Windows entfernen, für den für einige Dateien das schreibgeschützte Bit gesetzt ist. Es verwendet den onerror-Rückruf, um das schreibgeschützte Bit zu löschen und das Entfernen erneut zu versuchen. Jeder nachfolgende Fehler wird sich ausbreiten.

import os, stat
import shutil

def remove_readonly(func, path, _):
    "Clear the readonly bit and reattempt the removal"
    os.chmod(path, stat.S_IWRITE)
    func(path)

shutil.rmtree(directory, onerror=remove_readonly)
Dave Chandler
quelle
7
import os
import stat
import shutil

def errorRemoveReadonly(func, path, exc):
    excvalue = exc[1]
    if func in (os.rmdir, os.remove) and excvalue.errno == errno.EACCES:
        # change the file to be readable,writable,executable: 0777
        os.chmod(path, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)  
        # retry
        func(path)
    else:
        # raiseenter code here

shutil.rmtree(path, ignore_errors=False, onerror=errorRemoveReadonly) 

Wenn ignore_errors gesetzt ist, werden Fehler ignoriert. Wenn onerror gesetzt ist, wird es aufgerufen, um den Fehler mit Argumenten (func, path, exc_info) zu behandeln, wobei func os.listdir, os.remove oder os.rmdir ist. Pfad ist das Argument für diese Funktion, die zum Fehlschlagen geführt hat. und exc_info ist ein Tupel, das von sys.exc_info () zurückgegeben wird. Wenn ignore_errors false und onerror None ist, wird hier eine Ausnahme ausgelöst. Geben Sie Code ein

RY Zheng
quelle
Laut den Dokumenten werden von onerror ausgelöste Ausnahmen nicht abgefangen, daher bin ich mir nicht sicher , ob Ihr Code für die Eingabe von Erhöhungen hier etwas bedeutet.
kmarsh
-1. Dies scheint im Vergleich zu Dave Chandlers Antwort zu kompliziert. Wenn wir schreibgeschützt entfernen möchten, müssen wir die Dateien nicht ausführbar machen.
idbrii
7

Überprüfen Sie anhand der Antwort von kkubasik, ob der Ordner vorhanden ist, bevor Sie ihn entfernen

import shutil
def remove_folder(path):
    # check if folder exists
    if os.path.exists(path):
         # remove if exists
         shutil.rmtree(path)
    else:
         # throw your exception to handle this special scenario
         raise XXError("your exception") 
remove_folder("/folder_name")
Charles Chow
quelle
6
Dies führt eine mögliche Rennbedingung ein
Corey Goldberg
1
Laut der meisten Python-Methode zum Löschen einer Datei, die möglicherweise nicht vorhanden ist , ist es vorzuziehen, sie zu tryentfernen und zu verarbeiten, exceptals sie exists()zuerst
aufzurufen
6

Wenn Sie sicher sind, dass Sie den gesamten Verzeichnisbaum löschen möchten und sich nicht mehr für den Inhalt von dir interessieren, ist es dumm, nach dem gesamten Verzeichnisbaum zu kriechen. Rufen Sie dazu einfach den nativen Betriebssystembefehl von Python auf. Es wird schneller, effizienter und weniger speicherintensiv sein.

RMDIR c:\blah /s /q 

oder * nix

rm -rf /home/whatever 

In Python sieht der Code wie folgt aus:

import sys
import os

mswindows = (sys.platform == "win32")

def getstatusoutput(cmd):
    """Return (status, output) of executing cmd in a shell."""
    if not mswindows:
        return commands.getstatusoutput(cmd)
    pipe = os.popen(cmd + ' 2>&1', 'r')
    text = pipe.read()
    sts = pipe.close()
    if sts is None: sts = 0
    if text[-1:] == '\n': text = text[:-1]
    return sts, text


def deleteDir(path):
    """deletes the path entirely"""
    if mswindows: 
        cmd = "RMDIR "+ path +" /s /q"
    else:
        cmd = "rm -rf "+path
    result = getstatusoutput(cmd)
    if(result[0]!=0):
        raise RuntimeError(result[1])
PM
quelle
33
-1. Der springende Punkt bei der Verwendung shutil.rmdirist, Sie von der Art des Betriebssystems zu isolieren.
mtrw
3
Ich verstehe das Konzept, aber wenn man sich der Tatsache bewusst ist, dass er den Ordner vollständig löschen möchte, was bringt es dann, den gesamten Dateibaum zu crawlen? shutil.rmdir ruft speziell os.listdir (), os.path.islink () usw. usw. auf. Einige Überprüfungen, die nicht immer benötigt werden, da nur die Verknüpfung des Dateisystemknotens aufgehoben werden muss. Neben einigen Build-Systemen, wie z. B. MSWindows für die MSAuto / WinCE-Entwicklung, schlägt shtuil.rmdir fast immer fehl, da die stapelbasierte Entwicklung von MSAuto einige seltsame Build-Dateien beim erfolglosen Beenden sperrt und nur rmdir / S / Q oder ein Neustart zum Bereinigen hilfreich ist Sie.
PM
2
Ja, nur rm ist näher am Kernel, benötigt weniger Zeit, Speicher und CPU ..... und wie gesagt, der Grund für diese Methode war, dass MSAuto-Batch-Build-Skripte Sperren hinterlassen haben ...
PM
3
Ja, aber die Verwendung von shutil macht den Code plattformübergreifend und abstrahiert Plattformdetails.
Xshoppyx
2
Ich denke nicht, dass diese Antwort unter 1 herabgestuft werden sollte, da sie eine sehr gute Referenz für eine Problemumgehung für bestimmte Situationen darstellt, an denen ein Leser interessiert sein könnte. Ich genieße es, wenn mehrere Methoden in der richtigen Reihenfolge veröffentlicht werden. Obwohl ich dies nicht verwenden muss, weiß ich jetzt, dass es möglich ist und wie.
kmcguire
5

Nur einige Python 3.5-Optionen, um die obigen Antworten zu vervollständigen. (Ich hätte sie gerne hier gefunden).

import os
import shutil
from send2trash import send2trash # (shutil delete permanently)

Ordner löschen, wenn leer

root = r"C:\Users\Me\Desktop\test"   
for dir, subdirs, files in os.walk(root):   
    if subdirs == [] and files == []:
           send2trash(dir)
           print(dir, ": folder removed")

Löschen Sie auch den Ordner, wenn er diese Datei enthält

    elif subdirs == [] and len(files) == 1: # if contains no sub folder and only 1 file 
        if files[0]== "desktop.ini" or:  
            send2trash(dir)
            print(dir, ": folder removed")
        else:
            print(dir)

Ordner löschen, wenn er nur .srt- oder .txt-Dateien enthält

    elif subdirs == []: #if dir doesn’t contains subdirectory
        ext = (".srt", ".txt")
        contains_other_ext=0
        for file in files:
            if not file.endswith(ext):  
                contains_other_ext=True
        if contains_other_ext== 0:
                send2trash(dir)
                print(dir, ": dir deleted")

Ordner löschen, wenn seine Größe weniger als 400 KB beträgt:

def get_tree_size(path):
    """Return total size of files in given path and subdirs."""
    total = 0
    for entry in os.scandir(path):
        if entry.is_dir(follow_symlinks=False):
            total += get_tree_size(entry.path)
        else:
            total += entry.stat(follow_symlinks=False).st_size
    return total


for dir, subdirs, files in os.walk(root):   
    If get_tree_size(dir) < 400000:  # ≈ 400kb
        send2trash(dir)
    print(dir, "dir deleted")
JinSnow
quelle
4
Bitte if files[0]== "desktop.ini" or:
korrigieren
5

Ich möchte einen "reinen Pathlib" -Ansatz hinzufügen:

from pathlib import Path
from typing import Union

def del_dir(target: Union[Path, str], only_if_empty: bool = False):
    target = Path(target).expanduser()
    assert target.is_dir()
    for p in sorted(target.glob('**/*'), reverse=True):
        if not p.exists():
            continue
        p.chmod(0o666)
        if p.is_dir():
            p.rmdir()
        else:
            if only_if_empty:
                raise RuntimeError(f'{p.parent} is not empty!')
            p.unlink()
    target.rmdir()

Dies beruht auf der Tatsache, dass Pathes ordentlich ist und längere Pfade immer nach kürzeren Pfaden sortieren, genau wie str. Daher werden Verzeichnisse vor Dateien stehen. Wenn wir umkehren die Sortierung , werden die Dateien vor ihren jeweiligen Containern angezeigt, sodass wir sie einfach einzeln mit einem Durchgang trennen / rmdiren können.

Leistungen:

  • Es ist NICHT auf externe Binärdateien angewiesen: Alles verwendet Pythons Module, die in Batterien enthalten sind (Python> = 3.6).
  • Es ist schnell und speichereffizient: Kein Rekursionsstapel, kein Unterprozess muss gestartet werden
  • Es ist plattformübergreifend (zumindest ist es das, was pathlib verspricht dies in Python 3.6; kein oben angegebener Vorgang soll nicht unter Windows ausgeführt werden)
  • Bei Bedarf kann eine sehr detaillierte Protokollierung durchgeführt werden, z. B. jede Löschung wird protokolliert, sobald dies geschieht.
pepoluan
quelle
können Sie auch ein Verwendungsbeispiel angeben, z. del_dir (Pfad ())? Danke
lcapra
@lcapra Rufen Sie es einfach mit dem zu löschenden Verzeichnis als erstes Argument auf.
Pepoluan
3
def deleteDir(dirPath):
    deleteFiles = []
    deleteDirs = []
    for root, dirs, files in os.walk(dirPath):
        for f in files:
            deleteFiles.append(os.path.join(root, f))
        for d in dirs:
            deleteDirs.append(os.path.join(root, d))
    for f in deleteFiles:
        os.remove(f)
    for d in deleteDirs:
        os.rmdir(d)
    os.rmdir(dirPath)
erstaunlich da
quelle
Hervorragend geeignet, um ein Skript zu erstellen, mit dem die Datei in Quarenteen gestellt wird, bevor sie blind entfernt werden.
Racribeiro
3

Wenn Sie das shutilModul nicht verwenden möchten, können Sie es einfach verwenden os.

from os import listdir, rmdir, remove
for i in listdir(directoryToRemove):
    os.remove(os.path.join(directoryToRemove, i))
rmdir(directoryToRemove) # Now the directory is empty of files
Byron Filer
quelle
2
os.removeVerzeichnisse können nicht entfernt werden, daher wird dies ausgelöst, OsErrorwenn directoryToRemoveUnterverzeichnisse enthalten sind.
Gleichnamig
#pronetoraceconditions
Kapad
3

Zehn Jahre später und unter Verwendung von Python 3.7 und Linux gibt es noch verschiedene Möglichkeiten, dies zu tun:

import subprocess
from pathlib import Path

#using pathlib.Path
path = Path('/path/to/your/dir')
subprocess.run(["rm", "-rf", str(path)])

#using strings
path = "/path/to/your/dir"
subprocess.run(["rm", "-rf", path])

Im Wesentlichen wird das Unterprozessmodul von Python verwendet, um das Bash-Skript $ rm -rf '/path/to/your/dirso auszuführen, als würden Sie das Terminal verwenden, um dieselbe Aufgabe auszuführen . Es ist nicht vollständig Python, aber es schafft es.

Der Grund, warum ich das pathlib.PathBeispiel aufgenommen habe, ist, dass es meiner Erfahrung nach sehr nützlich ist, wenn es um viele Pfade geht, die sich ändern. Die zusätzlichen Schritte zum Importieren des pathlib.PathModuls und zum Konvertieren der Endergebnisse in Zeichenfolgen sind für mich oft weniger Kosten für die Entwicklungszeit. Es wäre praktisch, wenn Sie Path.rmdir()eine arg-Option hätten, um nicht leere Verzeichnisse explizit zu behandeln.

RodogInfinite
quelle
Ich habe auch auf diesen Ansatz umgestellt, weil ich auf Probleme mit rmtreeund versteckte Ordner wie gestoßen bin .vscode. Dieser Ordner wurde als Textdatei erkannt und der Fehler sagte mir, dass diese Datei busygelöscht wurde und nicht gelöscht werden konnte.
Daniel Eisenreich
2

So löschen Sie einen Ordner, auch wenn er möglicherweise nicht vorhanden ist (Vermeidung der Race-Bedingung in Charles Chows Antwort ), aber dennoch Fehler, wenn andere Fehler auftreten (z. B. Berechtigungsprobleme, Fehler beim Lesen der Festplatte, die Datei ist kein Verzeichnis)

Für Python 3.x:

import shutil

def ignore_absent_file(func, path, exc_inf):
    except_instance = exc_inf[1]
    if isinstance(except_instance, FileNotFoundError):
        return
    raise except_instance

shutil.rmtree(dir_to_delete, onerror=ignore_absent_file)

Der Python 2.7-Code ist fast der gleiche:

import shutil
import errno

def ignore_absent_file(func, path, exc_inf):
    except_instance = exc_inf[1]
    if isinstance(except_instance, OSError) and \
        except_instance.errno == errno.ENOENT:
        return
    raise except_instance

shutil.rmtree(dir_to_delete, onerror=ignore_absent_file)
Gleichnamig
quelle
1

Mit os.walk würde ich die Lösung vorschlagen, die aus 3 einzeiligen Python-Aufrufen besteht:

python -c "import sys; import os; [os.chmod(os.path.join(rs,d), 0o777) for rs,ds,fs in os.walk(_path_) for d in ds]"
python -c "import sys; import os; [os.chmod(os.path.join(rs,f), 0o777) for rs,ds,fs in os.walk(_path_) for f in fs]"
python -c "import os; import shutil; shutil.rmtree(_path_, ignore_errors=False)"

Das erste Skript chmod enthält alle Unterverzeichnisse, das zweite Skript chmod enthält alle Dateien. Dann entfernt das dritte Skript alles ohne Hindernisse.

Ich habe dies anhand des "Shell-Skripts" in einem Jenkins-Job getestet (ich wollte kein neues Python-Skript in SCM speichern, deshalb wurde nach einer einzeiligen Lösung gesucht) und es funktionierte für Linux und Windows.

Alexander Samoylov
quelle
Mit pathlibkönnen Sie die ersten beiden Schritte zu einem kombinieren:[p.chmod(0o666) for p in pathlib.Path(_path_).glob("**/*")]
pepoluan
0

Der Einfachheit halber können Sie den Befehl os.system verwenden:

import os
os.system("rm -rf dirname")

Es ist offensichtlich, dass das Systemterminal aufgerufen wird, um diese Aufgabe auszuführen.


quelle
19
Entschuldigung, dies ist unpythonisch und plattformabhängig.
Ami Tavory
0

Ich habe eine sehr einfache Möglichkeit gefunden, einen Ordner (auch NICHT leer) oder eine Datei unter WINDOWS OS zu löschen .

os.system('powershell.exe  rmdir -r D:\workspace\Branches\*%s* -Force' %CANDIDATE_BRANCH)
Seremet
quelle
0

Für Windows, wenn das Verzeichnis nicht leer ist und Sie schreibgeschützte Dateien haben oder Fehler wie erhalten

  • Access is denied
  • The process cannot access the file because it is being used by another process

Versuche dies, os.system('rmdir /S /Q "{}"'.format(directory))

Es ist gleichbedeutend rm -rfmit Linux / Mac.

Kartik Raj
quelle