Kasowanie folderów w pythonie rekurencyjnie

202

Mam problem z usunięciem pustych katalogów. Oto mój kod:

for dirpath, dirnames, filenames in os.walk(dir_to_search):
    //other codes

    try:
        os.rmdir(dirpath)
    except OSError as ex:
        print(ex)

Argument dir_to_searchpolega na tym, że przekazuję katalog, w którym należy wykonać pracę. Ten katalog wygląda następująco:

test/20/...
test/22/...
test/25/...
test/26/...

Pamiętaj, że wszystkie powyższe foldery są puste. Kiedy uruchomić ten skrypt foldery 20, 25sam zostaje usunięte! Ale foldery 25i 26nie są usuwane, nawet jeśli są pustymi folderami.

Edytować:

Wyjątek, który otrzymuję to:

[Errno 39] Directory not empty: '/home/python-user/shell-scripts/s3logs/test'
[Errno 39] Directory not empty: '/home/python-user/shell-scripts/s3logs/test/2012'
[Errno 39] Directory not empty: '/home/python-user/shell-scripts/s3logs/test/2012/10'
[Errno 39] Directory not empty: '/home/python-user/shell-scripts/s3logs/test/2012/10/29'
[Errno 39] Directory not empty: '/home/python-user/shell-scripts/s3logs/test/2012/10/29/tmp'
[Errno 39] Directory not empty: '/home/python-user/shell-scripts/s3logs/test/2012/10/28'
[Errno 39] Directory not empty: '/home/python-user/shell-scripts/s3logs/test/2012/10/28/tmp'
[Errno 39] Directory not empty: '/home/python-user/shell-scripts/s3logs/test/2012/10/26'
[Errno 39] Directory not empty: '/home/python-user/shell-scripts/s3logs/test/2012/10/25'
[Errno 39] Directory not empty: '/home/python-user/shell-scripts/s3logs/test/2012/10/27'
[Errno 39] Directory not empty: '/home/python-user/shell-scripts/s3logs/test/2012/10/27/tmp'

Gdzie popełniam błąd?

siriram
źródło
1
czy jesteś pewien, że nie mają ukrytych plików?
Jeff
Czy drukowany jest wyjątek lub ślad zwrotny? Jeśli tak, to pomogłoby, gdybyś dodał to do pytania
Ngure Nyaga,
@Jeff: Tak, jestem pewien. W rzeczywistości na mojej maszynie Ubuntu, którą próbowałem, rmdir /path/to/25th/folderusuwa cały katalog. Co oznacza, że ​​katalog jest pusty!
siriram
2
Możliwy duplikat Jak usunąć / usunąć folder, który nie jest pusty w Pythonie? na oba pytania ORAZ odpowiedź
Trevor Boyd Smith

Odpowiedzi:

391

Spróbuj shutil.rmtree:

import shutil
shutil.rmtree('/path/to/your/dir/')
Tomek
źródło
5
Czy rmtreeusunięto cały katalog? rm -Rf $DIR
Wydaje
7
Bądź ostrożny, ponieważ rmtree usuwa również pliki. Jak zadano, pytanie brzmiało: jak usunąć PUSTE katalogi. Dokumenty dla os.walk podają przykład, który prawie dokładnie pasuje do tego pytania: import os for root, dirs, files in os.walk(top, topdown=False): for name in dirs: os.rmdir(os.path.join(root, name))
DaveSawyer
Dokumentacja w wersji Python3: docs.python.org/3/library/shutil.html#shutil.rmtree
Vladimir Oprya
27

Domyślnym zachowaniem os.walk()jest przejście od korzenia do liścia. Ustaw topdown=Falsew os.walk()chodzić z liści do korzenia.

lqs
źródło
18

Oto mój czysty pathlibrekurencyjny program do usuwania katalogu:

from pathlib import Path

def rmdir(directory):
    directory = Path(directory)
    for item in directory.iterdir():
        if item.is_dir():
            rmdir(item)
        else:
            item.unlink()
    directory.rmdir()

rmdir(Path("dir/"))
mitch
źródło
12

Spróbuj rmtree()się shutilze standardowej biblioteki Pythona

microo8
źródło
1
Czy rmtreeusunięto cały katalog? rm -Rf $DIR
Wydaje
2
z dokumentów: „Usuń całe drzewo katalogów; ścieżka musi wskazywać na katalog (ale nie symboliczne łącze do katalogu). Jeśli true jest ignore_errors, błędy wynikające z nieudanych operacji usuwania zostaną zignorowane; jeśli są fałszywe lub pominięte, takie błędy są obsługiwane wywołując moduł obsługi określony przez onerror lub, jeśli zostanie pominięty, zgłaszają wyjątek. ”
microo8,
7

lepiej użyć ścieżki bezwzględnej i zaimportować tylko funkcję rmtree, from shutil import rmtree ponieważ jest to duży pakiet, powyższa linia zaimportuje tylko wymaganą funkcję.

from shutil import rmtree
rmtree('directory-absolute-path')
Gajender
źródło
1
Odniosłbyś się do tego jako rmtree(); nieshutil.rmtree()
Kevin Murphy
4

Tylko dla następnego faceta szukającego rozwiązania mikrofytonowego działa to wyłącznie w oparciu o os (listdir, remove, rmdir). Nie jest ani kompletny (zwłaszcza w obsłudze błędów), ani wymyślny, jednak w większości przypadków będzie działał.

def deltree(target):
    print("deltree", target)
    for d in os.listdir(target):
        try:
            deltree(target + '/' + d)
        except OSError:
            os.remove(target + '/' + d)

    os.rmdir(target)
Justus Wingert
źródło
3

Polecenie (wydane przez Tomka) nie może usunąć pliku, jeśli jest tylko do odczytu . dlatego można użyć -

import os, sys
import stat

def del_evenReadonly(action, name, exc):
    os.chmod(name, stat.S_IWRITE)
    os.remove(name)

if  os.path.exists("test/qt_env"):
    shutil.rmtree('test/qt_env',onerror=del_evenReadonly)
Monir
źródło
2
podczas próby kod z moim własnym folderze mają być usunięte, pojawia się błąd mówiąc: NameError: name 'stat' is not defined. Jak to zostało zdefiniowane?
nnako
1
Moduł stat definiuje stałe i funkcje do interpretacji wyników os.stat (), os.fstat () i os.lstat (). co możesz wypróbować: importuj os, sys z statystyki import *
Monir
0

Oto inne rozwiązanie z czystą ścieżką , ale bez rekurencji:

from pathlib import Path
from typing import Union

def del_empty_dirs(base: Union[Path, str]):
    base = Path(base)
    for p in sorted(base.glob('**/*'), reverse=True):
        if p.is_dir():
            p.chmod(0o666)
            p.rmdir()
        else:
            raise RuntimeError(f'{p.parent} is not empty!')
    base.rmdir()
pepoluan
źródło
-1

Oto rozwiązanie rekurencyjne:

def clear_folder(dir):
    if os.path.exists(dir):
        for the_file in os.listdir(dir):
            file_path = os.path.join(dir, the_file)
            try:
                if os.path.isfile(file_path):
                    os.unlink(file_path)
                else:
                    clear_folder(file_path)
                    os.rmdir(file_path)
            except Exception as e:
                print(e)
Tobias Ernst
źródło
-1

Użytkownicy systemu Linux mogą po prostu uruchomić polecenie powłoki w sposób pythonowy

import os
os.system("rm -r /home/user/folder_name")

gdzie rmoznacza Usuń i -rdla rekurencyjnie

Garvit
źródło