shutil.rmtree для удаления файлов только для чтения

Я хочу использовать shutil.rmtree в Python, чтобы удалить каталог. Указанный каталог содержит .git управляющий каталог, который помечает git как доступный только для чтения и скрытый.

Флаг только для чтения вызывает rmtree терпеть неудачу. В Powershell я бы сделал "del -force" для принудительного удаления флага только для чтения. Есть ли эквивалент в Python? Я бы предпочел не ходить по всему дереву дважды, но onerror Аргумент к rmtree, похоже, не повторяет операцию, поэтому я не могу использовать

def set_rw(operation, name, exc):
    os.chmod(name, stat.S_IWRITE)

shutil.rmtree('path', onerror=set_rw)

4 ответа

Решение

После более подробного изучения, кажется, работает следующее:

def del_rw(action, name, exc):
    os.chmod(name, stat.S_IWRITE)
    os.remove(name)
shutil.rmtree(path, onerror=del_rw)

Другими словами, фактически удалите файл в функции onerror. (Возможно, вам придется проверить каталог в обработчике onerror и использовать rmdir в этом случае - мне это не нужно, но это может быть что-то конкретное в моей проблеме.

shutil.rmtree используется для удаления непустых каталогов (удаление дерева).

      
    import os
    import stat
    import shutil
    def del_ro_dir(dir_name):
        '''Remove Read Only Directories'''
        for (root, dirs, files) in os.walk(dir_name, topdown=True):
            os.chmod(root,
                # For user ...
                stat.S_IRUSR |
                stat.S_IWUSR |
                stat.S_IXUSR |
                # For group ...
                stat.S_IWGRP |
                stat.S_IRGRP |
                stat.S_IXGRP |
                # For other ...
                stat.S_IROTH |
                stat.S_IWOTH |
                stat.S_IXOTH
            )
        shutil.rmtree(dir_name)

    if __name__ == '__main__':
        del_ro_dir('dir_name_here')

Чтобы удалить только файл, вы можете использовать следующий код:

      
    import os
    import stat
    def rmv_rof(file_name):
        '''Remov Read Only Files'''
        if os.path.exists(file_name):
            os.chmod(file_name, stat.S_IWRITE)
            os.remove(file_name)
        else:
            print('The file does not exist.')
    rmv_rof('file_name_here')

Вы можете прочитать подробную информацию здесь:

https://docs.python.org/3/library/os.html#os.chmod

https://docs.python.org/3/library/stat.html#module-stat

https://docs.python.org/3/library/shutil.html#rmtree-example

Вы могли бы просто пойти быстрым и грязным методом и сделать subprocess.check_call(["rm", "-rf", filename]). Скорее всего, не будет работать в Windows.

Вотrmtreeпример , скопированный прямо изshutilдокументы (вероятно, добавленные после ОП):

       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, onexc=remove_readonly)

Обратите внимание, что есть небольшая разница в принятом ответе: в приведенном выше примере используетсяfuncаргумент, а не явный вызовos.remove.

Также обратите внимание, чтоonerrorустарел с версии Python 3.12 и будет заменен наonexc.

Другие вопросы по тегам