비어 있지 않은 폴더는 어떻게 제거 / 삭제합니까?


846

비어 있지 않은 폴더를 삭제하려고하면 '액세스가 거부되었습니다'오류가 발생합니다. 시도 할 때 다음 명령을 사용했습니다 os.remove("/folder_name")..

비어 있지 않은 폴더 / 디렉토리를 제거 / 삭제하는 가장 효과적인 방법은 무엇입니까?


32
또한 디렉토리가 비어 있어도 올바른 기능은 os.rmdir이므로 os.remove는 다시 실패합니다.
tzot

그리고 특정의 대한 rm -rf행동을 참조하십시오 stackoverflow.com/questions/814167/...
치로 틸리가冠状病毒审查六四事件法轮功

답변:


1345
import shutil

shutil.rmtree('/folder_name')

표준 라이브러리 참조 : shutil.rmtree .

의도적으로 rmtree읽기 전용 파일이 포함 된 폴더 트리 에서는 실패합니다. 읽기 전용 파일이 포함되어 있는지 여부에 관계없이 폴더를 삭제하려면 다음을 사용하십시오.

shutil.rmtree('/folder_name', ignore_errors=True)

73
그 참고 rmtree: 읽기 전용 파일이있는 경우 실패합니다 stackoverflow.com/questions/2656322/...
스리 Ratnakumar

9
이것은 나를 위해 작동하지 않습니다 : Traceback (가장 최근 호출) : <module> shut31.rmtree (thistestdir) 파일 "/usr/lib/python2.6/shutil.py의 31 행"foo.py "파일 rmtree onerror (os.rmdir, path, sys.exc_info ()) 파일의 225 행, rmtree os.rmdir (path)의 223 행, "/usr/lib/python2.6/shutil.py"파일 223 행 OSError : [errno를 90] 디렉토리가 비어 있지 : '/ 경로 /에 / rmtree'
클레이튼 휴즈

4
Clayton : rmtree가 파일을 삭제하는 중 파일이 동시에 추가 된 경우 "rm -rf"도 동일하게 실패합니다.
ddaa

13
이 기능이 왜 os 패키지에 없는지 아는 사람이 있습니까? os.rmdir은 매우 쓸모없는 것 같습니다. 왜 이런 식으로 구현되었는지에 대한 좋은 주장이 있습니까?
Malcolm

21
@Malcolm 패키지는 OS 기능을위한 래퍼입니다. 에 POSIX의 시스템 RMDIR 디렉토리가 비어 있지 않으면 실패 할 것이다. 이 점에서 우분투Windows 는 POSIX 호환의 일반적인 예입니다.
Iain Samuel McLean Elder

138

에서 파이썬 문서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))

1
글쎄, 아마도 다운 모딩이 틀렸을 것이다. 하지만 지금은 옳다고 생각합니다.
ddaa

3
@ ddaa : shutil을 사용하는 것이 가장 쉬운 방법이지만이 솔루션에 대한 비열한 것은 없습니다. 나는이 대답을 upvoted하지 않았을,하지만 난 당신 downvote :) 상쇄 단지이 시간이
제레미 캔 트렐

7
코드 자체는 pythonic입니다. 실제 프로그램에서 shutil.rmtree 대신에 그것을 사용하는 것은 비현실적 일 것입니다. 어쨌든 이것은 의미 론적이며 다운 모드를 제거합니다.
ddaa

2
@ddaa 삭제 된 모든 파일이나 디렉토리를 기록하는 것은 비현실적입니까? shutil.rmtree로 어떻게하는지 모르겠습니다.
Jonathan Komar

4
@ddaa 그것은 생각, 즉 수사학을위한 음식이었습니다. 내가 뭘하는지 알아 shutil.rmtree가 올바른 "적합"이 아닌 이유를 제공하여 "명확한 방법"을 재고하고 싶다고 생각했습니다.
조나단 코 마르

112
import shutil
shutil.rmtree(dest, ignore_errors=True)

1
이것이 정답입니다. 내 시스템에서는 특정 폴더의 모든 것을 쓰기 읽기로 설정했지만 삭제하려고 할 때 오류가 발생합니다. ignore_errors=True문제를 해결합니다.
Aventinus

3
내 대답에는 onerror매개 변수가 대신 사용됩니다 ignore_errors. 이렇게하면 읽기 전용 파일이 무시되지 않고 삭제됩니다.
Dave Chandler

예, 오류가 발생해도 파일을 삭제하지 않습니다. 따라서 기본적으로 전체 rmtree()방법이 무시됩니다.
Juha Untinen

1
이것은 6 년 전에 받아 들여진 답변에 대한 약간의 수정 이었지만 새로운 답변이었습니다. 지금 할게요
Jean-François Corbett

22

파이썬 3.4에서 사용할 수 있습니다 :

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 dir content, remove this line

인스턴스 pth는 어디에 있습니까 pathlib.Path? 좋지만 가장 빠르지는 않을 수 있습니다.


10

에서 docs.python.org :

이 예는 일부 파일에 읽기 전용 비트가 설정된 Windows에서 디렉토리 트리를 제거하는 방법을 보여줍니다. 읽기 전용 비트를 지우고 제거를 다시 시도하기 위해 onerror 콜백을 사용합니다. 후속 실패는 전파됩니다.

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)

7
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) 

ignore_errors가 설정되면 오류가 무시됩니다. 그렇지 않으면, onerror가 설정되면 인수 (func, path, exc_info)로 오류를 처리하기 위해 호출됩니다. 여기서 func는 os.listdir, os.remove 또는 os.rmdir입니다. path는 실패한 함수에 대한 인수입니다. exc_info는 sys.exc_info ()에 의해 반환 된 튜플입니다. ignore_errors가 false이고 onerror가 None이면 예외가 발생합니다.


에 따르면 워드 프로세서 , 의 OnError에 의해 제기 예외가 잡힐 수 없습니다 나는 확실히 당신이 아니에요, 그래서 인상이 여기에 코드를 입력 것을 의미한다.
kmarsh

-1. Dave Chandler의 답변과 비교할 때 지나치게 복잡해 보입니다. 또한 읽기 전용을 제거하려면 파일을 실행 파일로 만들 필요가 없습니다.
idbrii

7

kkubasik의 답변을 바탕으로 폴더를 제거하기 전에 폴더가 있는지 확인하십시오.

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")

6
이것은 가능한 경쟁 조건을 소개합니다
Corey Goldberg

1
에 따라 가장 파이썬 - 방법 - 투 - 삭제-A-파일있는 월 -하지 - 존재 , 그것은하는 것이 바람직의 try제거 및 핸들 except호출보다 exists()먼저
TT--

6

확실하다면, 전체 디렉토리 트리를 삭제하고 더 이상 디렉토리 내용에 관심이 없다면 전체 디렉토리 트리를 크롤링하는 것은 어리 석음입니다 ... 파이썬에서 네이티브 OS 명령을 호출하면됩니다. 더 빠르고 효율적이며 메모리 소비가 적습니다.

RMDIR c:\blah /s /q 

또는 * nix

rm -rf /home/whatever 

파이썬에서는 코드가 다음과 같습니다.

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])

33
-1. 사용의 요점 shutil.rmdir은 운영 체제 유형으로부터 사용자를 격리시키는 것입니다.
mtrw

3
개념을 이해하지만 폴더를 완전히 삭제한다는 사실을 잘 알고 있다면 전체 파일 트리를 크롤링하는 시점은 무엇입니까? shutil.rmdir은 특히 os.listdir (), os.path.islink () 등을 호출합니다. 파일 시스템 노드를 링크 해제하는 것이 실제로 필요하기 때문에 실제로는 항상 필요한 것은 아닙니다. MSAuto / WinCE 개발을위한 MSWindows와 같은 일부 빌드 시스템 외에, MSAuto 배치 기반 개발은 실패한 종료시 일부 빌드 파일을 잠그고 rmdir / S / Q 또는 재시작 만 청소하면 도움이되므로 shtuil.rmdir은 거의 항상 실패합니다. 그들.
PM

2
그래, 그냥 rm은 더 적은 시간, 메모리 및 CPU를 사용하여 커널에 더 가깝습니다 ..... 그리고 내가 말했듯이,이 방법을 사용하는 이유는 MSAuto 배치 빌드 스크립트에 의해 남겨진 잠금 때문이었습니다 ...
PM

3
예. 그러나 shutil을 사용하면 코드가 크로스 플랫폼으로 만들어지고 플랫폼 세부 정보가 추상화됩니다.
xshoppyx

2
이 답변은 독자가 관심을 가질 수있는 특정 상황에 대한 해결 방법에 대한 아주 좋은 참고 자료를 제공하기 때문에 1 이하로 투표하지 않아야한다고 생각합니다. 나는 여러 방법을 순서대로 게시하는 것을 즐깁니다. 따라서 이것을 사용할 필요는 없지만 이제는 수행 할 수있는 방법과 방법을 알고 있습니다.
kmcguire

5

위의 답변을 완료하기 위해 일부 Python 3.5 옵션이 있습니다. (여기서 그들을 찾고 싶었을 것입니다).

import os
import shutil
from send2trash import send2trash # (shutil delete permanently)

비어있는 경우 폴더 삭제

root = r"C:\Users\Me\Desktop\test"   
for dir, subdirs, files in os.walk(root):   
    if subdirs == [] and files == []:
           send2trash(dir)
           print(dir, ": folder removed")

이 파일이 포함 된 폴더도 삭제

    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)

.srt 또는 .txt 파일 만 포함 된 폴더 삭제

    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")

크기가 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")

4
들여 쓰기 및 코드 수정if files[0]== "desktop.ini" or:
Mr_and_Mrs_D

5

"pure pathlib"접근 방식을 추가하고 싶습니다 :

from pathlib import Path
from typing import Union

def del_dir(target: Union[Path, str], only_if_empty: bool = False):
    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()

이것은 순서 Path가 정해져 있다는 사실에 의존하며, 더 긴 경로는 항상처럼 짧은 경로를 따라 정렬됩니다 str. 따라서 디렉토리는 파일보다 우선합니다. 정렬 을 반대로 바꾸면 파일이 해당 컨테이너보다 먼저 나오므로 패스별로 하나씩 링크를 해제 / rmdir 할 수 있습니다.

혜택:

  • 외부 바이너리에 의존하지 않습니다. 모든 것이 파이썬의 배터리 포함 모듈을 사용합니다 (Python> = 3.6)
  • 빠르고 메모리 효율적입니다. 재귀 스택이 없으며 하위 프로세스를 시작할 필요가 없습니다.
  • 그것은 크로스 플랫폼입니다 (적어도, 그것은 pathlibPython 3.6에서 약속하는 것입니다. 위의 작업은 Windows에서 실행되지 않는다고 명시되어 있지 않습니다)
  • 필요한 경우 매우 세밀한 로깅을 수행 할 수 있습니다 (예 : 각 삭제가 발생할 때마다 로깅).

사용 예도 제공 할 수 있습니까? del_dir (경로)? 감사합니다
lcapra

@lcapra 단순히 디렉토리로 호출하여 첫 ​​번째 인수로 삭제하십시오.
페폴 루안

3
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)

파일을 맹목적으로 제거하기 전에 파일을 채석장에 넣는 스크립트를 만드는 것이 좋습니다.
racribeiro

3

shutil모듈 을 사용하지 않으려면 모듈을 사용하면 os됩니다.

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

2
os.remove디렉토리를 제거 할 수 없으므로 서브 디렉토리 OsErrordirectoryToRemove포함되어 있으면 증가 합니다 .
시조

#pronetoraceconditions
kapad

3

10 년 후 Python 3.7과 Linux를 사용하는 방법은 여전히 ​​다른 방법입니다.

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])

본질적으로 파이썬의 하위 프로세스 모듈을 $ rm -rf '/path/to/your/dir사용하여 동일한 작업을 수행하기 위해 터미널을 사용하는 것처럼 bash 스크립트를 실행합니다 . 완전히 파이썬은 아니지만 완료됩니다.

내가 pathlib.Path예제를 포함시킨 이유는 내 경험상 변경되는 많은 경로를 다룰 때 매우 유용하기 때문입니다. pathlib.Path모듈 을 가져오고 최종 결과를 문자열로 변환하는 추가 단계 는 종종 개발 시간에 저비용입니다. Path.rmdir()비어 있지 않은 디렉토리를 명시 적으로 처리하기 위해 arg 옵션을 사용하면 편리합니다 .


또한 rmtree이와 같은 폴더에 숨겨진 문제가 발생하여이 방법으로 전환했습니다 .vscode. 이 폴더는 텍스트 파일로 감지되었으며이 파일이 busy삭제 되었으며 삭제할 수 없다는 오류 가 표시됩니다.
Daniel Eisenreich

2

폴더가 존재하지 않더라도 ( Charles Chow의 답변 에서 경쟁 조건을 피할 수 있음) 폴더를 삭제 하지만 다른 일이 잘못되었을 때 여전히 오류가 발생합니다 (예 : 권한 문제, 디스크 읽기 오류, 파일이 디렉토리가 아닙니다)

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)

파이썬 2.7 코드는 거의 같습니다 :

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)

1

os.walk를 사용하면 3 개의 one-liner Python 호출로 구성된 솔루션을 제안합니다.

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)"

첫 번째 스크립트 chmod는 모든 하위 디렉토리이고, 두 번째 스크립트 chmod는 모든 파일입니다. 그런 다음 세 번째 스크립트는 장애없이 모든 것을 제거합니다.

Jenkins 작업의 "Shell Script"에서 이것을 테스트했습니다 (SCM에 새로운 Python 스크립트를 저장하고 싶지 않기 때문에 한 줄 솔루션을 검색 한 이유입니다) .Linux 및 Windows에서 작동했습니다.


을 사용 pathlib하면 처음 두 단계를 하나로 결합 할 수 있습니다.[p.chmod(0o666) for p in pathlib.Path(_path_).glob("**/*")]
pepoluan

0

간단하게 os.system 명령을 사용할 수 있습니다.

import os
os.system("rm -rf dirname")

명백히, 실제로이 작업을 수행하기 위해 시스템 터미널을 호출합니다.


19
죄송합니다. Unpythonic 및 플랫폼에 따라 다릅니다.
Ami Tavory

0

WINDOWS OS 에서 폴더 (비어 있지 않은 파일 ) 또는 파일 을 삭제하는 매우 쉬운 방법을 찾았습니다 .

os.system('powershell.exe  rmdir -r D:\workspace\Branches\*%s* -Force' %CANDIDATE_BRANCH)

0

Windows의 경우 디렉토리가 비어 있지 않고 읽기 전용 파일이 있거나 다음과 같은 오류가 발생하는 경우

  • Access is denied
  • The process cannot access the file because it is being used by another process

이 시도, os.system('rmdir /S /Q "{}"'.format(directory))

rm -rfLinux / Mac 과 동일합니다 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.