ChatGPT解决这个技术问题 Extra ChatGPT

Deleting folders in python recursively

I'm having a problem with deleting empty directories. Here is my code:

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

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

The argument dir_to_search is where I'm passing the directory where the work needs to be done. That directory looks like this:

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

Note that all the above folders are empty. When I run this script the folders 20,25 alone gets deleted! But the folders 25 and 26 aren't deleted, even though they are empty folders.

Edit:

The exception that I'm getting are:

[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'

Where am I making a mistake?

are you sure they don't have hidden files?
Is an exception or traceback printed? If so - it would help if you added that to the question
@Jeff: Yes I'm sure. In fact in my ubuntu machine I tried rmdir /path/to/25th/folder is deleting the entire directory. Which means that directory is an empty one!
Possible duplicate of How do I remove/delete a folder that is not empty with Python? of both question AND answer

B
Boris Verkhovskiy

Try shutil.rmtree:

import shutil
shutil.rmtree('/path/to/your/dir/')

Does the rmtree deleted the entire directory? I guess it is similar to the one rm -Rf $DIR
Be careful as rmtree deletes the files too. As asked, the question was how to delete EMPTY directories.The docs for os.walk give an example that almost exactly matches this question: import os for root, dirs, files in os.walk(top, topdown=False): for name in dirs: os.rmdir(os.path.join(root, name))
B
Boris Verkhovskiy

Here's my pure pathlib recursive directory unlinker:

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

It suppose be better that shutil, thus shutil is asynchronous
Very nice, and a tangible example of recursion as a bonus.
L
Leland Hepworth

The default behavior of os.walk() is to walk from root to leaf. Set topdown=False in os.walk() to walk from leaf to root.


B
Boris Verkhovskiy

Try rmtree() in shutil from the Python standard library


Does the rmtree deleted the entire directory? I guess it is similar to the one rm -Rf $DIR
from docs: "Delete an entire directory tree; path must point to a directory (but not a symbolic link to a directory). If ignore_errors is true, errors resulting from failed removals will be ignored; if false or omitted, such errors are handled by calling a handler specified by onerror or, if that is omitted, they raise an exception."
G
Gajender

better to use absolute path and import only the rmtree function from shutil import rmtree as this is a large package the above line will only import the required function.

from shutil import rmtree
rmtree('directory-absolute-path')

J
Justus Wingert

Just for the next guy searching for a micropython solution, this works purely based on os (listdir, remove, rmdir). It is neither complete (especially in errorhandling) nor fancy, it will however work in most circumstances.

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)

A
Azat Ibrakov

The command (given by Tomek) can't delete a file, if it is read only. therefore, one can use -

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)

when trying your code with my own folder to be deleted, I get an error saying: NameError: name 'stat' is not defined. How has it been defined?
The stat module defines constants and functions for interpreting the results of os.stat(), os.fstat() and os.lstat(). what you can try : import os, sys from stat import *
T
Tobias Ernst

Here is a recursive solution:

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)

C
Cireo

The command os.removedirs is the tool for the job, if you are only looking for a single path to delete, e.g.:

os.removedirs("a/b/c/empty1/empty2/empty3")

will remove empty1/empty2/empty3, but leave a/b/c (presuming that c has some other contents).

    removedirs(name)
        removedirs(name)
        
        Super-rmdir; remove a leaf directory and all empty intermediate
        ones.  Works like rmdir except that, if the leaf directory is
        successfully removed, directories corresponding to rightmost path
        segments will be pruned away until either the whole path is
        consumed or an error occurs.  Errors during this latter phase are
        ignored -- they generally mean that a directory was not empty.

p
pepoluan

Here's another pure-pathlib solution, but without recursion:

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

b
buhtz

Here is a pythonic and recursion-less solution

>>> for e in sorted(p.rglob('**/*'), key=lambda v: v.is_dir()):
...     try:
...         e.unlink()
...     except IsADirectoryError:
...         e.rmdir()

The rglob() gives you all files and directories recursively in the path p. The sorted() with its key argument takes care that the result is ordered by files first and directories at the end. This makes it possible to make all directories empty with deleting their files first.

The try...except... part prevents you from using cheap if statements.


G
Garvit

For Linux users, you can simply run the shell command in a pythonic way

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

If facing any issue then instead of rm -r use rm -rf but remember f will delete the directory forcefully.

Where rm stands for remove, -r for recursively and -rf for recursively + forcefully.

Note: It doesn't matter either the directories are empty or not, they'll get deleted.


when you use python however the code is system-dependent, it is no-longer pythonic.
@LukAron I've said, "shell command in a pythonic way" not only "pythonic way"