Como faço para remover / excluir uma pasta que não está vazia?

847

Estou recebendo um erro 'acesso negado' quando tento excluir uma pasta que não está vazia. Eu usei o seguinte comando na minha tentativa: os.remove("/folder_name").

Qual é a maneira mais eficaz de remover / excluir uma pasta / diretório que não está vazio?

Amara
fonte
32
Observe também que, mesmo que o diretório estivesse vazio, o os.remove falharia novamente, porque a função correta é os.rmdir.
tzot 19/11/08
E, para um rm -rfcomportamento específico , consulte: stackoverflow.com/questions/814167/…
Ciro Santilli ()

Respostas:

1349
import shutil

shutil.rmtree('/folder_name')

Referência da biblioteca padrão: shutil.rmtree .

Por design, rmtreefalha nas árvores de pastas que contêm arquivos somente leitura. Se você deseja que a pasta seja excluída, independentemente de conter arquivos somente leitura, use

shutil.rmtree('/folder_name', ignore_errors=True)
ddaa
fonte
73
Observe que rmtreefalhará se houver arquivos somente leitura: stackoverflow.com/questions/2656322/…
Sridhar Ratnakumar 16/04/2010
9
Isso não funciona para mim: Traceback (última chamada mais recente): arquivo "foo.py", linha 31, no <module> arquivo shutil.rmtree (thistestdir) "/usr/lib/python2.6/shutil.py ", linha 225, no arquivo rmtree onerror (os.rmdir, caminho, sys.exc_info ())" /usr/lib/python2.6/shutil.py ", linha 223, no arquivo rmtree os.rmdir (caminho) OSError: [Errno 90] Diretório não vazio: '/ path / to / rmtree'
Clayton Hughes
4
Clayton: com toda a probabilidade, um arquivo foi adicionado simultaneamente enquanto o rmtree estava ocupado excluindo coisas, "rm -rf" falharia o mesmo.
Ddaa
14
Alguém sabe por que essa funcionalidade não está no pacote os? Parece que os.rmdir é bastante inútil. Algum bom argumento para o porquê de ser implementado dessa maneira?
Malcolm
21
@ Malcolm O pacote é um invólucro para funções do SO. Nos sistemas POSIX , o rmdir falhará se o diretório não estiver vazio. Ubuntu e Windows são exemplos populares de conformidade com POSIX a esse respeito.
Iain Samuel McLean Elder
138

A partir dos documentos python em 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
fonte
1
Bem, talvez eu esteja errado em desclassificar. Mas eu posso, agora eu acho que está certo.
Ddaa 19/11/08
3
@ddaa: Embora o uso do shutil seja definitivamente a maneira mais fácil, certamente não há nada de antipático nessa solução. Eu não teria upvoted esta resposta, mas eu tenho só que desta vez para cancelar a sua downvote :)
Jeremy Cantrell
7
O código em si é pitônico. Usá-lo em vez de shutil.rmtree em um programa real seria antitônico: isso ignoraria a "única maneira óbvia de fazê-lo". Enfim, isso é semântica, removendo o downmod.
Ddaa
2
@ddaa Não é sintético querer registrar todos os arquivos ou diretórios que são excluídos? Não sei como fazer isso com shutil.rmtree?
precisa saber é o seguinte
4
@ddaa Era comida para pensar, isto é, retórica. Eu sei o que estou fazendo. Eu apenas pensei que você gostaria de reconsiderar "a maneira óbvia de fazê-lo", fornecendo uma razão pela qual shutil.rmtree pode não ser o "ajuste" certo.
precisa saber é o seguinte
112
import shutil
shutil.rmtree(dest, ignore_errors=True)
Siva Mandadi
fonte
1
Essa é a resposta correta. No meu sistema, mesmo que eu defina tudo na pasta específica para leitura / gravação, recebo um erro ao tentar excluir. ignore_errors=Trueresolve o problema.
Aventinus 07/10
3
Na minha resposta, o onerrorparâmetro é usado em vez de ignore_errors. Dessa maneira, os arquivos somente leitura são excluídos em vez de ignorados.
Dave Chandler
Sim, isso não excluirá os arquivos por erro. Então, basicamente, todo o rmtree()método é ignorado.
Juha Untinen
2
Essa deveria ter sido uma pequena edição da resposta aceita 6 anos antes, e sim uma nova resposta. Eu farei isso agora.
Jean-François Corbett
22

do python 3.4 você pode usar:

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

onde pthé uma pathlib.Pathinstância Bom, mas pode não ser o mais rápido.

yota
fonte
10

Do docs.python.org :

Este exemplo mostra como remover uma árvore de diretórios no Windows em que alguns dos arquivos têm o bit somente leitura definido. Ele usa o retorno de chamada onerror para limpar o bit somente leitura e tentar remover novamente. Qualquer falha subsequente será propagada.

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
fonte
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 ignore_errors estiver definido, os erros serão ignorados; caso contrário, se onerror for definido, ele será chamado para manipular o erro com argumentos (func, path, exc_info) em que func é os.listdir, os.remove ou os.rmdir; path é o argumento para essa função que causou a falha; e exc_info é uma tupla retornada por sys.exc_info (). Se ignore_errors for false e onerror for None, uma exceção será gerada.

RY Zheng
fonte
De acordo com os documentos , as exceções geradas pelo onerror não serão capturadas, portanto, não tenho certeza se o código de inserção do aumento aqui significa alguma coisa.
Kmarsh 3/11
-1. Isso parece complicado demais em comparação com a resposta de Dave Chandler. Além disso, se queremos remover somente leitura, não precisamos tornar os arquivos executáveis.
Idbrii 1/03/19
7

Com base na resposta do kkubasik, verifique se a pasta existe antes de remover, mais 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")
Charles Chow
fonte
6
isso introduz uma possível condição de corrida
Corey Goldberg
1
de acordo com a mais-pythônico-way-to-exclusão-a-file-que-pode-não-existir , é preferível tryremover e alça exceptde chamada exists()primeiro
TT--
6

se você tiver certeza de que deseja excluir toda a árvore de diretórios e não estiver mais interessado no conteúdo dele, rastrear toda a árvore de diretórios é estúpido ... basta chamar o comando nativo do SO do python para fazer isso. Será mais rápido, eficiente e consumirá menos memória.

RMDIR c:\blah /s /q 

ou * nix

rm -rf /home/whatever 

Em python, o código terá a aparência ..

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
fonte
33
-1. O objetivo principal do uso shutil.rmdiré isolá-lo do tipo de sistema operacional.
Mrw
3
Eu entendo o conceito, mas quando alguém está ciente do fato de que ele deseja excluir a pasta completamente, então qual é o sentido de rastrear toda a árvore de arquivos? shutil.rmdir chama especificamente os.listdir (), os.path.islink () etc etc .. algumas verificações que nem sempre são realmente necessárias, pois tudo o que é necessário é desvincular o nó do sistema de arquivos. Além de alguns sistemas de compilação, como o MSWindows para desenvolvimento do MSAuto / WinCE, o shtuil.rmdir falha quase sempre, pois o desenvolvimento baseado em lote do MSAuto bloqueia alguns arquivos estranhos de compilação na saída sem êxito e apenas o rmdir / S / Q ou restart é útil para limpar eles.
PM
2
sim, apenas a rm está mais próxima do kernel, usando menos tempo, memória e CPU ..... e como eu disse, o motivo para eu usar esse método foi devido aos bloqueios deixados pelos scripts de compilação em lote do MSAuto ...
PM
3
Sim, mas usar shutil torna o código multiplataforma e abstrai os detalhes da plataforma.
precisa saber é o seguinte
2
Não acho que essa resposta deva ser votada abaixo de 1, pois fornece uma referência muito boa para uma solução alternativa para determinadas situações em que um leitor possa estar interessado. Gosto de ter vários métodos publicados com eles classificados em ordem. Portanto, mesmo que eu não precise usar isso, agora sei que pode ser feito e como.
amigos estão
5

Apenas algumas opções do python 3.5 para concluir as respostas acima. (Eu adoraria encontrá-los aqui).

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

Excluir pasta se estiver vazio

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

Exclua também a pasta se ela contiver este arquivo

    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)

exclua a pasta se ela contiver apenas arquivos .srt ou .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")

Exclua a pasta se o tamanho for menor que 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")
JinSnow
fonte
4
Por favor, corrija a indentação e o códigoif files[0]== "desktop.ini" or:
Mr_and_Mrs_D
5

Eu gostaria de adicionar uma abordagem de "pathlib puro":

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

Isso depende do fato de Pathser ordenável, e caminhos mais longos sempre serão classificados após caminhos mais curtos, assim como str. Portanto, os diretórios virão antes dos arquivos. Se invertermos a classificação, os arquivos virão antes de seus respectivos contêineres, para que possamos simplesmente desvincular / rmdir deles um a um com uma passagem.

Benefícios:

  • NÃO depende de binários externos: tudo usa os módulos incluídos nas baterias do Python (Python> = 3.6)
  • É rápido e economiza memória: sem pilha de recursão, sem necessidade de iniciar um subprocesso
  • É multiplataforma (pelo menos, é o que pathlibpromete no Python 3.6; nenhuma operação acima mencionada não deve ser executada no Windows)
  • Se necessário, é possível fazer um registro muito granular, por exemplo, registrar cada exclusão à medida que ela acontece.
pepoluan
fonte
você também pode fornecer um exemplo de uso, por exemplo. del_dir (Path ())? Graças
lcapra
@lcapra Basta chamá-lo com o diretório para excluir como o primeiro argumento.
pepoluan 30/08/19
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)
incrível
fonte
É ótimo criar um script que coloque o arquivo em quarentena antes de removê-lo cegamente.
Racribeiro #
3

Se você não quiser usar o shutilmódulo, basta usá-lo 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
fonte
2
os.removenão pode remover diretórios, portanto, isso aumentará OsErrorse directoryToRemovecontiver subdiretórios.
Eponymous
#pronetoraceconditions
kapad
3

Dez anos depois, e usando Python 3.7 e Linux, ainda existem maneiras diferentes de fazer isso:

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

Essencialmente, ele está usando o módulo de subprocesso do Python para executar o script bash $ rm -rf '/path/to/your/dircomo se você estivesse usando o terminal para realizar a mesma tarefa. Não é totalmente Python, mas é feito.

A razão pela qual incluí o pathlib.Pathexemplo é porque, em minha experiência, é muito útil ao lidar com muitos caminhos que mudam. As etapas extras de importação do pathlib.Pathmódulo e conversão dos resultados finais em seqüências de caracteres costumam ser um custo menor para o tempo de desenvolvimento. Seria conveniente se Path.rmdir()viesse com uma opção arg para lidar explicitamente com diretórios não vazios.

RodogInfinite
fonte
Também mudei para essa abordagem, porque tive problemas com rmtreepastas ocultas como .vscode. Esta pasta foi detectada como arquivo de texto e o erro me informou que esse arquivo foi busye não pôde ser excluído.
Daniel Eisenreich 03/04
2

Para excluir uma pasta mesmo que ela não exista (evitando a condição de corrida na resposta de Charles Chow ), mas ainda tenha erros quando outras coisas derem errado (por exemplo, problemas de permissão, erro de leitura de disco, o arquivo não é um diretório)

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

O código Python 2.7 é quase o mesmo:

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)
Epônimo
fonte
1

Com o os.walk, eu proporia a solução que consiste em 3 chamadas Python de uma linha:

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

O primeiro script chmod é todos os subdiretórios, o segundo script chmod é todos os arquivos. Em seguida, o terceiro script remove tudo sem impedimentos.

Eu testei isso no "Shell Script" em um trabalho de Jenkins (não queria armazenar um novo script Python no SCM, por isso procurei uma solução de uma linha) e funcionou para Linux e Windows.

Alexander Samoylov
fonte
Com pathlib, você pode combinar as duas primeiras etapas em uma:[p.chmod(0o666) for p in pathlib.Path(_path_).glob("**/*")]
pepoluan
0

Você pode usar o comando os.system para simplificar:

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

Como óbvio, ele realmente chama o terminal do sistema para realizar esta tarefa.


fonte
19
Desculpe, isso não é atípico e depende da plataforma.
Ami Tavory
0

Eu encontrei uma maneira muito fácil de excluir qualquer pasta (mesmo que não esteja vazia) ou arquivo no sistema operacional WINDOWS .

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

Para Windows, se o diretório não estiver vazio e você tiver arquivos somente leitura ou tiver erros como

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

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

É equivalente rm -rfno Linux / Mac.

Kartik Raj
fonte