Come rimuovo / elimino una cartella che non è vuota?


847

Ricevo un errore "Accesso negato" quando tento di eliminare una cartella che non è vuota. Ho usato il seguente comando nel mio tentativo: os.remove("/folder_name").

Qual è il modo più efficace per rimuovere / eliminare una cartella / directory che non è vuota?


32
Si noti inoltre che anche se la directory fosse vuota, os.remove fallirebbe di nuovo, poiché la funzione corretta è os.rmdir.
tzot

Risposte:


1349
import shutil

shutil.rmtree('/folder_name')

Riferimenti alla libreria standard: shutil.rmtree .

Per impostazione rmtreepredefinita , non riesce sugli alberi delle cartelle contenenti file di sola lettura. Se si desidera eliminare la cartella indipendentemente dal fatto che contenga file di sola lettura, utilizzare

shutil.rmtree('/folder_name', ignore_errors=True)

73
Si noti che rmtreefallirà se ci sono file di sola lettura: stackoverflow.com/questions/2656322/...
Sridhar Ratnakumar

9
Questo non funziona per me: Traceback (ultima chiamata più recente): file "foo.py", linea 31, nel file <module> shutil.rmtree (thistestdir) "/usr/lib/python2.6/shutil.py ", linea 225, in rmtree onerror (os.rmdir, percorso, file sys.exc_info ())" /usr/lib/python2.6/shutil.py ", linea 223, in rmtree os.rmdir (percorso) OSError: [Errno 90] Directory non vuota: '/ path / to / rmtree'
Clayton Hughes

4
Clayton: con ogni probabilità, un file è stato aggiunto contemporaneamente mentre rmtree era impegnato a cancellare roba, "rm -rf" avrebbe fallito lo stesso.
ddaa,

14
Qualcuno sa perché questa funzionalità non è nel pacchetto OS? Sembra che os.rmdir sia abbastanza inutile. Qualche buona argomentazione sul perché è implementata in questo modo?
Malcolm,

21
@Malcolm Il pacchetto è un wrapper per le funzioni del sistema operativo. Sui sistemi POSIX rmdir fallirà se la directory non è vuota. Ubuntu e Windows sono esempi popolari di conformità POSIX al riguardo.
Iain Samuel McLean Elder il

138

Dai documenti di Python su 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))

1
Beh, forse mi sbaglio di sminuire. Ma posso, in questo momento penso che sia giusto.
dada

3
@ddaa: Sebbene l'utilizzo di shutil sia sicuramente il modo più semplice, non c'è certamente nulla di poco sincero in questa soluzione. Non avrei votato a favore di questa risposta, ma ho questa volta solo per cancellare il tuo voto negativo :)
Jeremy Cantrell,

7
Il codice stesso è pitonico. Usarlo al posto di shutil.rmtree in un vero programma sarebbe un falso: quello sarebbe ignorare "un modo ovvio di farlo". Comunque, questa è semantica, che rimuove il downmod.
dada

2
@ddaa Non è ritmico voler registrare ogni file o directory che viene eliminato? Non sono sicuro di come farlo con shutil.rmtree?
Jonathan Komar il

4
@ddaa Era cibo per la riflessione, cioè retorica. So cosa sto facendo. Ho solo pensato che potresti voler riconsiderare "il modo ovvio di farlo" fornendo una ragione per cui shutil.rmtree potrebbe non essere il giusto "adattamento".
Jonathan Komar,

112
import shutil
shutil.rmtree(dest, ignore_errors=True)

1
Questa è la risposta corretta Nel mio sistema, anche se ho impostato tutto nella cartella specifica per scrivere-leggere, ricevo un errore quando provo a eliminare. ignore_errors=Truerisolve il problema.
Aventinus,

3
Nella mia risposta onerrorviene utilizzato il parametro anziché ignore_errors. In questo modo i file di sola lettura vengono eliminati anziché ignorati.
Dave Chandler,

Sì, questo non eliminerà i file in caso di errore. Quindi sostanzialmente l'intero rmtree()metodo viene ignorato.
Juha Untinen,

2
Questo avrebbe dovuto essere una piccola modifica alla risposta accettata 6 anni prima, piuttosto una nuova risposta. Lo farò ora.
Jean-François Corbett,

22

da Python 3.4 puoi usare:

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

dove pthè un pathlib.Pathesempio. Bello, ma potrebbe non essere il più veloce.


10

Da docs.python.org :

Questo esempio mostra come rimuovere un albero di directory su Windows in cui alcuni dei file hanno il bit di sola lettura impostato. Utilizza il callback onerror per cancellare il bit di sola lettura e ritentare la rimozione. Eventuali insuccessi successivi si propagheranno.

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)

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) 

Se viene impostato ignore_errors, gli errori vengono ignorati; altrimenti, se onerror è impostato, viene chiamato per gestire l'errore con argomenti (func, path, exc_info) dove func è os.listdir, os.remove o os.rmdir; percorso è l'argomento di quella funzione che ha causato il fallimento; ed exc_info è una tupla restituita da sys.exc_info (). Se ignore_errors è falso e onerror è Nessuno, qui viene generata un'eccezione


Secondo i documenti , le eccezioni sollevate da onerror non verranno rilevate, quindi non sono sicuro che il tuo codice di immissione del rilancio qui significhi qualcosa.
km

-1. Ciò sembra complicato rispetto alla risposta di Dave Chandler. Inoltre, se vogliamo rimuovere in sola lettura, non è necessario rendere eseguibili i file.
idbrii

7

Basati sulla risposta di kkubasik, controlla se esiste una cartella prima di rimuoverla, più robusta

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")

6
questo introduce una possibile condizione di gara
Corey Goldberg

1
secondo la maggior parte-pitone-modo-di-cancellare-un-file-che-potrebbe-non-esistere , è preferibile tryrimuovere e gestire exceptpiuttosto che chiamare exists()prima
TT

6

se sei sicuro di voler eliminare l'intero albero di dir e non sei più interessato al contenuto di dir, allora la ricerca di un albero di dir è stupidità ... basta chiamare il comando del sistema operativo nativo da Python per farlo. Sarà più veloce, efficiente e richiede meno memoria.

RMDIR c:\blah /s /q 

o * nix

rm -rf /home/whatever 

In Python, il codice sarà simile a ..

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])

33
-1. Il punto centrale dell'utilizzo shutil.rmdirè quello di isolarti dal tipo di sistema operativo.
MTRW

3
Capisco il concetto, ma quando uno è ben consapevole del fatto che vuole eliminare completamente la cartella, qual è il punto di eseguire la scansione dell'intero albero dei file? shutil.rmdir chiama in modo specifico os.listdir (), os.path.islink () ecc. ecc. alcuni controlli che non sono sempre realmente necessari, poiché tutto ciò che serve è scollegare il nodo del file system. Oltre ad alcuni sistemi di build, come MSWindows per lo sviluppo di MSAuto / WinCE, shtuil.rmdir fallirà quasi sempre, poiché lo sviluppo basato su batch di MSAuto blocca alcuni file di build strani in caso di uscita non riuscita e solo rmdir / S / Q o il riavvio sono utili per la pulizia loro.
PM

2
sì, solo rm è più vicino al kernel, usando meno tempo, memoria e CPU ..... e come ho detto, la ragione per cui ho usato questo metodo era a causa dei blocchi lasciati dagli script di compilazione batch di MSAuto ...
PM

3
Sì, ma l'utilizzo di shutil rende il codice multipiattaforma e estrae i dettagli della piattaforma.
xshoppyx

2
Non credo che questa risposta debba essere votata al di sotto di 1 in quanto fornisce un ottimo riferimento per aggirare alcune situazioni in cui un lettore potrebbe essere interessato. Mi piace avere più metodi pubblicati con loro classificati in ordine. Quindi, anche se non ho bisogno di usare questo, ora so che può essere fatto e come.
kmcguire,

5

Solo alcune opzioni di Python 3.5 per completare le risposte sopra. (Mi sarebbe piaciuto trovarli qui).

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

Elimina la cartella se vuota

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")

Elimina anche la cartella se contiene questo file

    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)

elimina cartella se contiene solo file .srt o .txt

    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")

Elimina la cartella se la sua dimensione è inferiore a 400kb:

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")

4
Correggi l'indentatyion e il codiceif files[0]== "desktop.ini" or:
Mr_and_Mrs_D il

5

Vorrei aggiungere un approccio "pure pathlib":

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()

Ciò si basa sul fatto che Pathè ordinabile e i percorsi più lunghi verranno sempre ordinati dopo percorsi più brevi, proprio come str. Pertanto, le directory verranno prima dei file. Se invertiamo l'ordinamento, i file verranno prima dei rispettivi contenitori, quindi possiamo semplicemente scollegarli / rmdirli uno per uno con un passaggio.

Benefici:

  • NON si basa su binari esterni: tutto utilizza i moduli inclusi nelle batterie di Python (Python> = 3.6)
  • È veloce ed efficiente in termini di memoria: nessuno stack di ricorsione, non è necessario avviare un sottoprocesso
  • È multipiattaforma (almeno, questo è ciò che pathlibpromette in Python 3.6; nessuna operazione sopra dichiarata non può essere eseguita su Windows)
  • Se necessario, è possibile eseguire una registrazione molto granulare, ad esempio, registrare ogni eliminazione in tempo reale.

puoi fornire anche un esempio di utilizzo es. del_dir (Path ())? Grazie
lcapra,

@lcapra Basta chiamarlo con la directory per eliminarlo come primo argomento.
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)

Ottimo per creare script che mettono il file in quarantena prima di rimuoverli alla cieca.
racribeiro,

3

Se non vuoi usare il shutilmodulo, puoi semplicemente usare il osmodulo.

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

2
os.removeimpossibile rimuovere le directory, quindi questo aumenterà OsErrorse directoryToRemovecontiene sottodirectory.
Eponimo

#pronetoraceconditions
kapad

3

Dieci anni dopo e usando Python 3.7 e Linux ci sono ancora diversi modi per farlo:

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])

Essenzialmente sta usando il modulo di sottoprocesso di Python per eseguire lo script bash $ rm -rf '/path/to/your/dircome se stessi usando il terminale per svolgere la stessa attività. Non è completamente Python, ma lo fa.

Il motivo per cui ho incluso l' pathlib.Pathesempio è perché nella mia esperienza è molto utile quando ho a che fare con molti percorsi che cambiano. I passaggi aggiuntivi per l'importazione del pathlib.Pathmodulo e la conversione dei risultati finali in stringhe rappresentano spesso un costo inferiore per i tempi di sviluppo. Sarebbe conveniente se Path.rmdir()fornito con un'opzione arg per gestire esplicitamente dirs non vuoti.


Sono anche passato a questo approccio, perché ho riscontrato problemi con rmtreecartelle nascoste come .vscode. Questa cartella è stata rilevata come file di testo e l'errore mi ha detto che questo file era busye non poteva essere eliminato.
Daniel Eisenreich,

2

Per eliminare una cartella anche se potrebbe non esistere (evitando la condizione di competizione nella risposta di Charles Chow ) ma avere ancora errori quando altre cose vanno male (ad esempio problemi di autorizzazione, errore di lettura del disco, il file non è una directory)

Per 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)

Il codice Python 2.7 è quasi lo stesso:

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)

1

Con os.walk proporrei la soluzione che consiste in 3 chiamate Python one-liner:

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)"

Il primo script chmod è tutto sottodirectory, il secondo script chmod è tutto file. Quindi il terzo script rimuove tutto senza impedimenti.

Ho provato questo da "Shell Script" in un lavoro Jenkins (non volevo salvare un nuovo script Python in SCM, ecco perché cercavo una soluzione a una riga) e funzionava per Linux e Windows.


Con pathlib, è possibile combinare i primi due passaggi in uno:[p.chmod(0o666) for p in pathlib.Path(_path_).glob("**/*")]
pepoluan

0

È possibile utilizzare il comando os.system per semplicità:

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

Come ovvio, in realtà invoca il terminale di sistema per eseguire questa operazione.


19
Siamo spiacenti, questo è Unpythonic e dipende dalla piattaforma.
Ami Tavory,

0

Ho trovato un modo molto semplice per eliminare qualsiasi cartella (anche NON vuota) o file sul sistema operativo WINDOWS .

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

0

Per Windows, se la directory non è vuota e hai file di sola lettura o ricevi errori come

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

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

È equivalente per rm -rfLinux / Mac.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.