radicaled
radicaled

Reputation: 2669

Delete a directory that is not empty on python

So, I need to clean a directory that is not empty. I have created the following function.For testing reasons I tried to remove a JDK installation

def clean_dir(location):
    fileList = os.listdir(location)

    for fileName in fileList:
        fullpath=os.path.join(location, fileName)
        if os.path.isfile(fullpath):
            os.chmod(fullpath, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)
            os.remove(location + "/" + fileName)
        elif os.path.isdir(fullpath):
            if len(os.listdir(fullpath)) > 0:
                clean_dir(fullpath)
            #os.rmdir(location + "/" + fileName)
            shutil.rmtree(location + "/" + fileName)

    return

I tried to use rmtree and rmdir, but it fails.

The error I got using rmtree is:

OSError: Cannot call rmtree on a symbolic link

And this is the error I got when I used rmdir:

OSError: [Errno 66] Directory not empty: '/tmp/jdk1.8.0_25/jre/lib/amd64/server'

The code works correctly on windows. But for some reason it fails on linux.

Upvotes: 0

Views: 6528

Answers (2)

radicaled
radicaled

Reputation: 2669

kronenpj thanks, that was the idea. But when you have a symlink it tries to delete is as a normal file and fails. I had to add a new elif and add the unlink option for the symlink

def clean_dir(location):
    fileList = os.listdir(location)

for fileName in fileList: fullpath=os.path.join(location, fileName) if os.path.isfile(fullpath): os.chmod(fullpath, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO) os.remove(os.path.join(location, fileName)) elif os.path.islink(fullpath): os.unlink(fullpath) elif os.path.isdir(fullpath): if len(os.listdir(fullpath)) > 0: clean_dir(fullpath) #os.rmdir(location + "/" + fileName) shutil.rmtree(os.path.join(location, fileName)) return

Upvotes: 2

kronenpj
kronenpj

Reputation: 221

You're encountering one of the differences between the way Windows and Linux (UNIX really) handle filesystems. I believe adding an additional case to your code will at least help:

...
for fileName in fileList:
    fullpath = os.path.join(location, fileName)
    ## |<-- Handle symlink -->|
    if os.path.islink(fullpath) or os.path.isfile(fullpath):
        os.chmod(fullpath, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)
        os.remove(os.path.join(location, fileName))
    elif os.path.isdir(fullpath):
        if len(os.listdir(fullpath)) > 0:
            clean_dir(fullpath)
        #os.rmdir(os.path.join(location, fileName))
        shutil.rmtree(os.path.join(location, fileName))
...

This should properly handle the case where the entry is a symlink and remove it just like a file. I'm not sure the chmod is necessary - it probably works on the target of the link, but it shouldn't hurt to handle it the same way as a file.

However, I just checked and os.path.file against a symbolic link returns the type of the "thing" that is pointed to, so the additional check is needed to differentiate between the link itself and the thing pointed to. Also to be portable, instead of appending "/" use os.path.join as newly edited above.

Upvotes: 3

Related Questions