0

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.

3
  • You are pointing rmtree at a symbolic link, not a directory. en.wikipedia.org/wiki/Symbolic_link Commented Jul 16, 2016 at 0:14
  • If it's a symbolic link, I think os.unlink(...) is all you need. (To clarify, that will just remove the symbolic link. It won't delete anything the symbolic link points to.) Commented Jul 16, 2016 at 0:15
  • IIRC, os.unlink should delete files as well. Commented Jul 16, 2016 at 1:55

2 Answers 2

3

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.

Sign up to request clarification or add additional context in comments.

Comments

2

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

1 Comment

Absolutely correct, I wasn't sure about whether remove() would properly handle symlinks or not.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.