91

What is the easiest way to do the equivalent of rm -rf in Python?

Marco Bonelli
  • 63,369
  • 21
  • 118
  • 128
Josh Gibson
  • 21,808
  • 28
  • 67
  • 63
  • 1
    Possible duplicate of [How do I remove/delete a folder that is not empty with Python?](http://stackoverflow.com/questions/303200/how-do-i-remove-delete-a-folder-that-is-not-empty-with-python) – Trevor Boyd Smith Nov 04 '16 at 19:23

8 Answers8

96
import shutil
shutil.rmtree("dir-you-want-to-remove")
Greg Hewgill
  • 951,095
  • 183
  • 1,149
  • 1,285
Josh Gibson
  • 21,808
  • 28
  • 67
  • 63
47

While useful, rmtree isn't equivalent: it errors out if you try to remove a single file, which rm -f does not (see example below).

To get around this, you'll need to check whether your path is a file or a directory, and act accordingly. Something like this should do the trick:

import os
import shutil

def rm_r(path):
    if os.path.isdir(path) and not os.path.islink(path):
        shutil.rmtree(path)
    elif os.path.exists(path):
        os.remove(path)

Note: this function will not handle character or block devices (that would require using the stat module).

Example in difference of between rm -f and Python's shutils.rmtree

$ mkdir rmtest
$ cd rmtest/
$ echo "stuff" > myfile
$ ls
myfile
$ rm -rf myfile 
$ ls
$ echo "stuff" > myfile
$ ls
myfile
$ python
Python 2.7.1+ (r271:86832, Apr 11 2011, 18:13:53) 
[GCC 4.5.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import shutil
>>> shutil.rmtree('myfile')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/shutil.py", line 236, in rmtree
    onerror(os.listdir, path, sys.exc_info())
  File "/usr/lib/python2.7/shutil.py", line 234, in rmtree
    names = os.listdir(path)
OSError: [Errno 20] Not a directory: 'myfile'

Edit: handle symlinks; note limitations as per @pevik's comment

Gabriel Grant
  • 5,415
  • 2
  • 32
  • 40
  • 2
    This version does't work on symlinks to directories as python returns `True` on `os.path.isdir(symlink_to_directory)` – pevik Oct 01 '15 at 07:15
  • Good catch, @pevik -- fixed it. Thanks! – Gabriel Grant Oct 05 '15 at 13:36
  • 1
    This doesn't work for directories where the permissions disallow it, but you are root. At a shell prompt, you will get prompted "override rw------ for File.txt?" unless you use the -f flag. That works silently at the prompt while up above in python fails. – Matt Sep 13 '18 at 21:13
  • `os.remove` removes devices just fine; I just tried it. I don't understand the remarks about the code not working on device files and such. The POSIX syscall `unlink` doesn't distinguish between files and devices. – Kaz Oct 06 '19 at 00:03
  • this somehow does not work when the folder is a git repository, error message `PermissionError: [WinError 5] Access is denied: 'C:\\Codes\\team_lib\\temp_FR_537562\\.git\\objects\\pack\\pack-****.idx` – XYZ Aug 19 '22 at 07:02
  • 1
    @XYZ not 100% sure this is the issue you're running into, but Windows often will not let you remove files if they're currently open by another process, and (at least in wsl) that is reported as a permission error that appears to be very similar to the error you'd receive if you didn't have write access to the file. is it possible that something is issuing/monitoring that directory? (I've often found VScode to be a culprit) – Gabriel Grant Sep 11 '22 at 00:25
  • @GabrielGrant, I agree. Most likely some git related files are opened in the cache in the VScode? I am not sure myself. But if I close all the programs and run in cmd, it solves the problem. – XYZ Sep 12 '22 at 01:15
6
import os
import shutil

def rm_r(path):
    if not os.path.exists(path):
        return
    if os.path.isfile(path) or os.path.islink(path):
        os.unlink(path)
    else:
        shutil.rmtree(path)

Slightly improved Gabriel Grant's version. This works also on symlinks to directories.

Note: function does not handle Un*x character and block devices (it would require to use stat module).

pevik
  • 4,523
  • 3
  • 33
  • 44
  • 1
    You can probably handle devices by putting the `unlink` into the fallback case; do `rmtree` if you detect a directory. I.e. we don't have to specifically test for device node types. – Kaz Oct 05 '19 at 23:57
1

I know shutil.rmtree() is the recommended approach, but for me, it is just not reliable. I was running into instances where API would fail and the directory was not deleted.

The most robust approach I've found is:

import subprocess
import os

def remove_dir(d):
    if os.name == 'nt':
        subprocess.check_output(['cmd', '/C', 'rmdir', '/S', '/Q', os.path.abspath(d)])
    else:
        subprocess.check_output(['rm', '-rf', os.path.abspath(d)])
driedler
  • 3,750
  • 33
  • 26
0
def delite(filepath):

    import os, stat, sys
    def intertwin(_list):
        list1 = []
        for i in _list:
            list1 += i
        return list1
    allpath = os.walk(filepath)
    walk = []
    dirs = []
    path = []
    allfiles = []
    for i in allpath:
        walk.append(i)
    for i in walk:
        dirs.append(i[0])
    for _dir in dirs:
        os.chdir(_dir)
        files = os.listdir(_dir)
        files1 = []
        for i in files:
            files1.append(_dir + '\\' + i)
        files = files1[:]
        allfiles.append(files)
    allfiles = intertwin(allfiles)
    for i in allfiles:
        os.chmod(i, stat.S_IRWXU)
    allfiles.reverse()
    os.chdir(sys.path[0])
    for i in allfiles:
        try:
            os.remove(i)
        except:
            try:
                os.rmdir(i)
            except:
                pass
    os.chmod(filepath, stat.S_IRWXU)
    try:
        os.remove(filepath)
    except:
        os.rmdir(filepath)
        allfiles.reverse()
        os.chdir(sys.path[0])
        for i in allfiles:
            try:
                os.remove(i)
            except:
                try:
                    os.rmdir(i)
                except:
                    pass
        os.chmod(filepath, stat.S_IRWXU)
        try:
            os.remove(filepath)
        except:
            os.rmdir(filepath)
Banghua Zhao
  • 1,518
  • 1
  • 14
  • 23
Pogramist
  • 35
  • 3
  • Удаляет папку с файлами или файл, даже если стоит атрибут "Только чтение" Deletes a folder with files or a file, even if the attribute "Read only" – Pogramist May 28 '17 at 10:11
  • 1
    In English, please: _Deletes a folder with files or a file, even if attributed "Read only"_ – JosefZ May 28 '17 at 10:11
  • 1
    It was translater, i don't know english well)) – Pogramist May 28 '17 at 11:03
0

A workaround for Windows where it blocks deletion of file is to truncate the file:

outputFile = open(r"filename.txt","w") 
outputFile.truncate()
outputFile.close()
outputFile = open(r"filename.txt","a+") 

source: https://stackoverflow.com/a/2769090/6345724

dank8
  • 361
  • 4
  • 20
-2

shutil.rmtree() is right answer, but just look at another useful function - os.walk()

maxp
  • 5,454
  • 7
  • 28
  • 30
-9

Just do this:

import os
dirname = "path_to_directory_to_remove"
os.system("rm -rf %s" % dirname)