os.walk and recursive deletion
Peter Otten
__peter__ at web.de
Sat Oct 27 13:31:52 EDT 2007
Martin Marcher wrote:
> Hello,
>
> I'm playing around with os.walk and I made up del_tree(path) which I
> think is correct (in terms of the algorithm, but not as python wants
> it :)).
>
> As soon as some directory is deleted the iterator of os.walk chokes.
> OK that is somehow clear to me as it can't be valid anymore since it
> can't go to the just deleted directory but it is in the iterator.
>
> I generated the test data with (bash, don't know of other shell
> expansion features)
>
> # root="test"
> # mkdir $root
> # mkdir -p
> # $root/{a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z}/{a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z}
> # touch $root/{a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z}/{0,1,2,3,4,5,6,7,8,9}
> # touch $root/{a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z}/{a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z}/{0,1,2,3,4,5,6,7,8,9}
>
> Here goes the script, as far as I tested it it runs fine in test mode.
> Now that is just use the print statements like attached below. as soon
> as os.rmdir and os.unlink are involved the iterator chokes. How do I
> get around that, or what should I use to be able to recursively delete
> everything under a certain subdir?
>
> #--snip
> import sys
> import os
> import unittest
>
> def del_tree(path):
> walker = os.walk(path)
> for entry in walker:
> cwd = entry[0]
> subdirs = entry[1]
> files = entry[2]
> print "Checking directory: %s" %(cwd, )
> if files:
> for file in files:
> file = os.path.join(cwd, file)
> print "The file is now: %s" % (file, )
> #os.unlink(file)
> print "OK directory %s has no more files, checking for
> subdirs..." % (cwd, )
> else:
> print "OK directory %s NEVER HAD FILES, checking for
> subdirs..." % (cwd, )
> if not subdirs:
> print "We can delete: %s" % (cwd, )
> #os.rmdir(cwd)
> else:
> for subdir in subdirs:
> subdir = os.path.join(cwd, subdir)
> print "We need to recurse into: %s" % (subdir, )
> del_tree(subdir)
> #os.rmdir(path)
> print "Removing: %s" % (path, )
> #--snap
While it is possible to mix recursion and os.walk()...
def del_tree(path):
for cwd, subdirs, files in os.walk(path):
print "Checking directory: %s" %(cwd, )
if files:
for file in files:
file = os.path.join(cwd, file)
print "The file is now: %s" % (file, )
os.unlink(file)
print "OK directory %s has no more files, checking for subdirs..." % (cwd, )
else:
print "OK directory %s NEVER HAD FILES, checking for subdirs..." % (cwd, )
for subdir in subdirs:
subdir = os.path.join(cwd, subdir)
print "We need to recurse into: %s" % (subdir, )
del_tree(subdir)
break # ugly but necessary
print "Removing: %s" % (path, )
os.rmdir(path)
...the idea behind it is that you use it instead of recursion:
def del_tree(root):
for path, dirs, files in os.walk(root, False):
for fn in files:
os.unlink(os.path.join(path, fn))
for dn in dirs:
os.rmdir(os.path.join(path, dn))
os.rmdir(root)
The second parameter to os.walk() ensures that the tree is walked
depth-first, i. e. the contents of a directory are seen before the
directory itself. Personally, I would prefer a recursive implementation
based on os.listdir(),
def del_tree(root):
for name in os.listdir(root):
path = os.path.join(root, name)
if os.path.isdir(path):
del_tree(path)
else:
os.unlink(path)
os.rmdir(root)
an approach that is also taken by shutils.rmtree().
Peter
More information about the Python-list
mailing list