| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | |||
| 5 | 6 | 7 | 8 | 9 | 10 | 11 |
| 12 | 13 | 14 | 15 | 16 | 17 | 18 |
| 19 | 20 | 21 | 22 | 23 | 24 | 25 |
| 26 | 27 | 28 | 29 | 30 | 31 |
- win32com
- git
- 윈도우11
- Outlook
- 아웃룩
- 문자열
- 파이썬
- 오피스
- matlab
- Excel
- python
- Android
- Windows10
- 파이썬3
- pandas
- pythongui
- 엑셀
- VBA
- 파워포인트
- office
- Windows11
- windows
- html
- 깃
- 윈도우10
- 파이썬GUI
- pyqt5
- 안드로이드
- python3
- 비주얼베이직
Appia의 IT세상
파이썬 임시 파일, 실행 끝나면 지워야 한다 — Path.unlink()로 뒷정리하기 본문

▲ 파이썬 임시 파일, 실행 끝나면 지워야 한다 — Path.unlink()로 뒷정리하기
파이썬으로 업무 자동화를 하다 보면 중간에 '임시 파일'을 만드는 경우가 많습니다. 여러 PDF를 하나로 합치거나, 엑셀을 잠깐 PDF로 변환하거나, 압축을 풀었다가 다시 묶거나 — 결과물을 만드는 과정에서 잠깐 필요했다가 볼일이 끝나는 파일들이죠.
문제는 자동화 스크립트가 매일, 매시간 돈다는 겁니다. 이 임시 파일을 안 지우면 폴더에 merged.pdf, merged (1).pdf … 하루하루 쓰레기가 쌓입니다. 그래서 실전 코드 끝에는 늘 이 한 줄이 붙습니다.
if merged_path.exists():
merged_path.unlink() # 볼일 끝난 임시 파일 삭제
짧지만 왜 exists()를 먼저 보는지, unlink()가 정확히 무슨 뜻인지 알고 쓰는 분은 의외로 적습니다. 오늘 이 두 줄을 제대로 뜯어보겠습니다.
- 왜 '뒷정리'가 필요한가 — 자동화는 매일 돈다
- Path.unlink() — pathlib로 파일 지우기
- 왜 exists()를 먼저 확인하나
- 더 깔끔하게 — unlink(missing_ok=True)
- 실전 — 실패해도 반드시 지운다 (try / finally)
- 꼭 알아야 할 주의점 2가지
- 마무리
1. 왜 '뒷정리'가 필요한가 — 자동화는 매일 돈다
예를 들어 팀별 보고서 PDF 여러 개를 하나로 합쳐 메일로 보내는 자동화가 있다고 합시다. 과정은 이렇습니다.
merged.pdf 생성 (임시)② 이
merged.pdf를 메일에 첨부해 발송③ 발송 끝 →
merged.pdf는 이제 필요 없음 → 삭제merged.pdf는 최종 산출물이 아니라 '거쳐 가는' 파일입니다. 메일만 나가면 역할이 끝나죠. 그런데 ③번을 빼먹으면? 이 자동화가 매일 아침 돌 때마다 임시 파일이 남아, 한 달이면 폴더가 엉망이 되고 어떤 게 진짜 최신본인지도 헷갈리게 됩니다.
2. Path.unlink() — pathlib로 파일 지우기
파이썬 pathlib에서 파일 하나를 삭제하는 메서드가 바로 .unlink()입니다. 이름이 낯설 수 있는데, 리눅스에서 파일 삭제를 뜻하는 전통적인 용어가 unlink라 그대로 가져온 겁니다.
from pathlib import Path
merged_path = Path("output") / "merged.pdf"
merged_path.unlink() # 이 파일 하나를 삭제
예전 방식인 os.remove()와 하는 일은 똑같습니다. 다만 경로를 Path 객체로 다루면 / 로 경로를 잇고, .exists() · .unlink() 를 한 객체에서 자연스럽게 이어 쓸 수 있어 요즘은 pathlib을 권합니다.
| 하고 싶은 일 | pathlib 방식 |
|---|---|
| 파일 삭제 | path.unlink() |
| 빈 폴더 삭제 | path.rmdir() |
| 폴더 통째로(안 내용까지) 삭제 | shutil.rmtree(path) |
즉 unlink()는 딱 '파일 하나' 전용입니다. 폴더에는 못 씁니다(6번에서 다시 얘기합니다).
3. 왜 exists()를 먼저 확인하나
이제 맨 앞의 코드로 돌아옵니다. 왜 그냥 지우지 않고 if merged_path.exists(): 로 있는지 먼저 확인했을까요?
답은 간단합니다. 없는 파일을 지우려 하면 에러가 나기 때문입니다.
merged_path.unlink() # 파일이 없으면? # FileNotFoundError: [Errno 2] No such file or directory: 'output\merged.pdf' # 여기서 프로그램이 멈춰버린다
"이미 없으면 어차피 지울 필요도 없는데 왜 에러야?" 싶지만, 파이썬은 "지우라고 했는데 지울 대상이 없다"를 문제 상황으로 봅니다. 그래서 병합이 중간에 실패해서 merged.pdf가 아예 안 만들어진 경우, 뒷정리 코드가 오히려 새로운 에러를 터뜨리는 어이없는 일이 벌어집니다.
if merged_path.exists(): # 있을 때만
merged_path.unlink() # 지운다 → 에러 없음
exists()로 한 번 걸러주면, 파일이 있든 없든 이 코드는 조용히 제 할 일만 합니다. 자동화에서 "있으면 지우고, 없으면 그냥 넘어가라"는 게 딱 우리가 원하는 동작이죠.

▲ exists() 없이 삭제하면 FileNotFoundError로 멈춤 / exists() 체크 후에는 조용히 통과
4. 더 깔끔하게 — unlink(missing_ok=True)
사실 파이썬 3.8 이상이라면 이 2줄을 1줄로 줄일 수 있습니다. unlink()에 missing_ok=True 옵션을 주면 "없으면 그냥 넘어가라"는 뜻이 됩니다.
# 3.8 이상 — 이 한 줄이면 exists() 체크가 필요 없다 merged_path.unlink(missing_ok=True)
동작은 if exists(): unlink()와 사실상 같습니다. 파일이 있으면 지우고, 없으면 FileNotFoundError를 알아서 삼켜줍니다.

▲ exists() 먼저 확인하는 방식과 missing_ok=True 방식 — 동작은 같고 표현만 다르다
unlink(missing_ok=True)가 깔끔합니다. 다만 팀에 3.7 이하 환경이 섞여 있다면 이 옵션이 없어 에러가 나므로, 그때는 if exists() 방식이 안전합니다. 두 방식의 뜻이 같다는 것만 알면 됩니다.5. 실전 — 실패해도 반드시 지운다 (try / finally)
한 걸음 더 가봅시다. 메일 발송이 중간에 실패하면 어떻게 될까요? 아래처럼 짜면, 발송에서 에러가 나는 순간 아래 unlink()까지 도달하지 못하고 임시 파일이 남습니다.
merged_path = merge_pdfs(team_files) # 병합 → 임시 파일 생성 send_mail(merged_path) # ← 여기서 실패하면 merged_path.unlink(missing_ok=True) # ← 이 줄은 실행되지 않는다 (임시 파일 잔존)
그래서 "성공하든 실패하든 뒷정리는 반드시" 하려면 try / finally로 감싸줍니다. finally 블록은 에러가 나든 안 나든 무조건 실행되거든요.
merged_path = merge_pdfs(team_files) # 병합 → 임시 파일 생성
try:
send_mail(merged_path) # 실패할 수도 있는 작업
finally:
merged_path.unlink(missing_ok=True) # 성공/실패 무관 — 임시 파일은 항상 정리
finally에 두면 "작업이 실패해도 임시 파일은 남지 않는다"가 보장됩니다. 발송 실패는 실패대로 위로 올라가 알람이 울리고, 임시 파일은 임시 파일대로 깨끗이 치워지는 거죠. 실패 처리와 뒷정리는 별개라는 감각이 중요합니다.
▲ send_mail()이 성공하든 실패하든 finally의 unlink()는 무조건 실행된다
6. 꼭 알아야 할 주의점 2가지
① unlink()는 폴더에 쓸 수 없다.
unlink()는 파일 전용입니다. 폴더에 쓰면 IsADirectoryError(윈도우는 PermissionError)가 납니다. 빈 폴더는 rmdir(), 안에 파일이 든 폴더째로 지우려면 shutil.rmtree()를 씁니다.
② 휴지통이 아니다 — 즉시, 영구 삭제된다.
unlink()로 지운 파일은 휴지통으로 가지 않습니다. 곧바로 사라지고 되돌릴 수 없어요. 그래서 삭제 대상 경로가 정확한지 — 특히 사용자에게 받은 경로나 조립한 경로를 지울 때는 두 번 확인해야 합니다. "임시 파일만" 지우도록 내가 만든 파일 경로를 그대로 넘기는 게 안전합니다.휴지통으로 보내고 싶다면 send2trash 같은 별도 라이브러리가 있지만, 내가 방금 만든 임시 파일을 치우는 용도라면 그냥 unlink()로 충분합니다.
7. 마무리
if merged_path.exists(): merged_path.unlink() — 이 두 줄은 단순한 파일 삭제가 아니라, "내가 만든 임시 파일은 내가 치운다"는 자동화의 기본 예의입니다. 이 한 줄이 있고 없고가, 한 달 뒤 폴더의 깨끗함을 가릅니다.
Path.unlink()= 파일 하나 삭제 (os.remove와 동일)- 없는 파일을 지우면
FileNotFoundError→ 그래서exists()를 먼저 본다 - 3.8+ 는
unlink(missing_ok=True)한 줄로 대체 가능 - 실패해도 정리하려면
try / finally에 넣는다 - 폴더는
rmdir/shutil.rmtree· 휴지통 없이 영구 삭제임에 주의
이 "임시 파일 뒷정리" 패턴은 PDF 병합·변환·압축을 다루는 자동화 프로젝트마다 그대로 등장합니다. 결과물은 남기고 과정의 흔적은 지우는, 깔끔하게 도는 자동화의 마무리거든요. 다음 글에서는 tempfile 모듈로 애초에 안전한 임시 파일을 만드는 법을 다뤄보겠습니다.
