I am getting an ‘access is denied’ error when I attempt to delete a folder that is not empty. I used the following command in my attempt: os.remove("/folder_name").
What is the most effective way of removing/deleting a folder/directory that is not empty?
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
import shutil
shutil.rmtree('/folder_name')
Standard Library Reference: shutil.rmtree.
By design, rmtree fails on folder trees containing read-only files. If you want the folder to be deleted regardless of whether it contains read-only files, then use
shutil.rmtree('/folder_name', ignore_errors=True)
Method 2
From the python docs on 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))
Method 3
import shutil shutil.rmtree(dest, ignore_errors=True)
Method 4
from python 3.4 you may use :
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 the dir content but not the dir itself, remove this line
where pth is a pathlib.Path instance. Nice, but may not be the fastest.
Method 5
From docs.python.org:
This example shows how to remove a directory tree on Windows where
some of the files have their read-only bit set. It uses the onerror
callback to clear the readonly bit and reattempt the remove. Any
subsequent failure will propagate.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)
Method 6
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)
If ignore_errors is set, errors are ignored; otherwise, if onerror is set, it is called to handle the error with arguments (func, path, exc_info) where func is os.listdir, os.remove, or os.rmdir; path is the argument to that function that caused it to fail; and exc_info is a tuple returned by sys.exc_info(). If ignore_errors is false and onerror is None, an exception is raised.enter code here
Method 7
Base on kkubasik’s answer, check if folder exists before remove, more robust
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")
Method 8
I’d like to add a “pure pathlib” approach:
from pathlib import Path
from typing import Union
def del_dir(target: Union[Path, str], only_if_empty: bool = False):
"""
Delete a given directory and its subdirectories.
:param target: The directory to delete
:param only_if_empty: Raise RuntimeError if any file is found in the tree
"""
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()
This relies on the fact that Path is orderable, and longer paths will always sort after shorter paths, just like str. Therefore, directories will come before files. If we reverse the sort, files will then come before their respective containers, so we can simply unlink/rmdir them one by one with one pass.
Benefits:
- It’s NOT relying on external binaries: everything uses Python’s batteries-included modules (Python >= 3.6)
- Which means that it does not need to repeatedly start a new subprocess to do unlinking
- It’s quite fast & simple; you don’t have to implement your own recursion
- It’s cross-platform (at least, that’s what
pathlibpromises in Python 3.6; no operation above stated to not run on Windows) - If needed, one can do a very granular logging, e.g., log each deletion as it happens.
Method 9
Just some python 3.5 options to complete the answers above. (I would have loved to find them here).
import os
import shutil
from send2trash import send2trash # (shutil delete permanently)
Delete folder if empty
root = r"C:UsersMeDesktoptest"
for dir, subdirs, files in os.walk(root):
if subdirs == [] and files == []:
send2trash(dir)
print(dir, ": folder removed")
Delete also folder if it contains this 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)
delete folder if it contains only .srt or .txt file(s)
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")
Delete folder if its size is less than 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")
Method 10
Ten years later and using Python 3.7 and Linux there are still different ways to do this:
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])
Essentially it’s using Python’s subprocess module to run the bash script $ rm -rf '/path/to/your/dir as if you were using the terminal to accomplish the same task. It’s not fully Python, but it gets it done.
The reason I included the pathlib.Path example is because in my experience it’s very useful when dealing with many paths that change. The extra steps of importing the pathlib.Path module and converting the end results to strings is often a lower cost to me for development time. It would be convenient if Path.rmdir() came with an arg option to explicitly handle non-empty dirs.
Method 11
if you are sure, that you want to delete the entire dir tree, and are no more interested in contents of dir, then crawling for entire dir tree is stupidness… just call native OS command from python to do that. It will be faster, efficient and less memory consuming.
RMDIR c:blah /s /q
or *nix
rm -rf /home/whatever
In python, the code will look like..
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])
Method 12
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)
Method 13
To delete a folder even if it might not exist (avoiding the race condition in Charles Chow’s answer) but still have errors when other things go wrong (e.g. permission problems, disk read error, the file isn’t a directory)
For 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)
The Python 2.7 code is almost the same:
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)
Method 14
If you don’t want to use the shutil module you can just use the os module.
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
Method 15
With os.walk I would propose the solution which consists of 3 one-liner Python calls:
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)"
The first script chmod’s all sub-directories, the second script chmod’s all files. Then the third script removes everything with no impediments.
I have tested this from the “Shell Script” in a Jenkins job (I did not want to store a new Python script into SCM, that’s why searched for a one-line solution) and it worked for Linux and Windows.
Method 16
For Windows, if directory is not empty, and you have read-only files or you get errors like
Access is deniedThe process cannot access the file because it is being used by another process
Try this, os.system('rmdir /S /Q "{}"'.format(directory))
It’s equivalent for rm -rf in Linux/Mac.
Method 17
Recursion-based, pure pathlib solution:
from pathlib import Path
def remove_path(path: Path):
if path.is_file() or path.is_symlink():
path.unlink()
return
for p in path.iterdir():
remove_path(p)
path.rmdir()
Supports Windows and symbolic links
Method 18
You can use os.system command for simplicity:
import os
os.system("rm -rf dirname")
As obvious, it actually invokes system terminal to accomplish this task.
Method 19
I have found a very easy way to Delete any folder(Even NOT Empty) or file on WINDOWS OS.
os.system('powershell.exe rmdir -r D:workspaceBranches*%s* -Force' %CANDIDATE_BRANCH)
Method 20
In my case the only way to delete was by using all possibilities because my code was supposed to run either by cmd.exe or powershell.exe. If it is your case, just create a function with this code and you will be fine:
#!/usr/bin/env python3
import shutil
from os import path, system
import sys
# Try to delete the folder ---------------------------------------------
if (path.isdir(folder)):
shutil.rmtree(folder, ignore_errors=True)
if (path.isdir(folder)):
try:
system("rd -r {0}".format(folder))
except Exception as e:
print("WARN: Failed to delete => {0}".format(e),file=sys.stderr)
if (path.isdir(self.backup_folder_wrk)):
try:
system("rd /s /q {0}".format(folder))
except Exception as e:
print("WARN: Failed to delete => {0}".format(e),file=sys.stderr)
if (path.isdir(folder)):
print("WARN: Failed to delete {0}".format(folder),file=sys.stderr)
# -------------------------------------------------------------------------------------
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0