중복 파일 삭제 스크립트를 돌렸다가 식은땀 흘린 날
중복 파일 삭제 스크립트를 돌렸다가 식은땀 흘린 날
이 블로그의 중복 파일 자동 삭제 편과 파일명 일괄 변경 편을 보면 공통적으로 "DRY_RUN"이라는 안전장치가 들어 있습니다. 실제 삭제나 변경 전에 미리보기부터 하도록 만든 이 습관은, 사실 처음부터 있던 게 아니라 한 번의 아찔한 경험 뒤에 생긴 것입니다.
당시 상황은 이랬습니다. 다운로드 폴더가 오래 방치되어 있어 용량을 확인해보니 중복 파일이 상당히 많았고, "파일 해시값을 비교해서 중복이면 자동으로 지우는" 스크립트를 처음 짜서 바로 실행했습니다.
사건 발생 — 실행 버튼을 누른 직후
처음 짠 코드는 대략 이런 형태였습니다.
import hashlib
from pathlib import Path
from collections import defaultdict
folder = Path(r"C:\Users\내이름\Downloads")
hash_map = defaultdict(list)
def get_hash(filepath):
h = hashlib.md5()
with open(filepath, "rb") as f:
h.update(f.read())
return h.hexdigest()
for file in folder.rglob("*"):
if file.is_file():
hash_map[get_hash(file)].append(file)
# 중복이면 첫 번째만 남기고 나머지 삭제
for files in hash_map.values():
if len(files) > 1:
for f in files[1:]:
f.unlink() # ← 바로 삭제 실행
print(f"삭제: {f.name}")
실행하자마자 터미널에 "삭제: ..." 로그가 빠르게 스크롤되기 시작했습니다. 처음 몇 줄은 정말로 중복된 다운로드 파일들이었어서 흐뭇하게 지켜보고 있었는데, 로그 중간에 낯익은 파일명이 스쳐 지나갔습니다. 업무용 엑셀 서식 파일이었습니다.
❌ 무엇이 잘못됐나: "파일 내용이 완전히 같으면 중복"이라는 로직 자체는 맞았지만, 문제는 같은 서식 파일을 여러 프로젝트 폴더에 의도적으로 복사해서 보관하고 있었다는 점이었습니다. 스크립트 입장에서는 "내용이 같은 중복 파일"이지만, 저에게는 각각 다른 프로젝트에 필요한 "의도된 사본"이었습니다.
다행히 큰 사고로 이어지지 않은 이유
다행히 이 상황은 최악으로 치닫지 않았습니다. 두 가지 우연 덕분이었습니다.
첫째, Ctrl+C로 중간에 강제 종료했습니다. 낯익은 파일명을 본 순간 반사적으로 터미널 창에서 Ctrl+C를 눌렀고, 다행히 스크립트가 전체 폴더를 다 처리하기 전에 멈췄습니다.
둘째, 지워진 파일 중 하나가 최근에 다른 폴더에도 백업해둔 파일이었습니다. 완전히 유일한 원본이 아니라 어딘가에 복사본이 남아있어서 복구할 수 있었습니다.
하지만 이건 순전히 운이었습니다. Ctrl+C를 누르는 타이밍이 1초만 늦었어도, 혹은 그 파일의 복사본이 다른 곳에 없었다면 되돌릴 수 없는 손실이었을 것입니다.
그날 이후 바뀐 것 — DRY_RUN이라는 습관
이 일을 겪고 나서 삭제나 이름 변경처럼 되돌릴 수 없는 작업을 하는 모든 스크립트에 예외 없이 적용하게 된 원칙이 있습니다.
# 개선된 방식: 삭제 전에 반드시 목록부터 보여주기
DRY_RUN = True # ← 항상 True로 시작
for files in hash_map.values():
if len(files) > 1:
for f in files[1:]:
if DRY_RUN:
print(f"[미리보기] 삭제 예정: {f}") # 실제 삭제 안 함
else:
f.unlink()
print(f"삭제 완료: {f.name}")
이 원칙은 지금 이 블로그의 중복 파일 자동 삭제 편과 파일명 일괄 변경 편에 그대로 반영되어 있습니다. 두 글 모두 DRY_RUN = True 상태로 먼저 실행해서 결과를 눈으로 확인한 뒤에야 실제 삭제·변경을 진행하도록 구조를 짰습니다. 당시에는 "번거롭게 왜 두 번 실행해야 하나"라고 생각했을 수도 있지만, 이제는 이 두 번째 확인 과정이 없는 삭제 스크립트는 아예 만들지 않습니다.
돌아보며 — "일단 다 지우면 되지"라는 생각의 위험성
자동화 스크립트를 처음 만들 때 흔히 하는 실수가, 논리적으로 맞는 규칙(내용이 같으면 중복)을 세우고 나면 그 규칙이 항상 옳다고 확신해버리는 것입니다. 하지만 실제 파일 시스템에는 "의도된 중복"이 존재할 수 있습니다. 같은 파일을 여러 프로젝트에 의도적으로 복사해두거나, 백업 목적으로 똑같은 파일을 여러 곳에 두는 경우가 그렇습니다.
이 경험 이후로 지키게 된 원칙은 단순합니다. "되돌릴 수 없는 작업일수록 미리보기 단계를 절대 생략하지 않는다." 코드가 아무리 논리적으로 완벽해 보여도, 실제 파일 시스템의 맥락(왜 이 파일이 여기 있는지)까지 코드가 알 수는 없기 때문입니다.
핵심 요약
- 사건: 중복 파일 자동 삭제 스크립트가 의도적으로 복사해둔 업무 파일까지 삭제하기 시작함
- 원인: "내용이 같으면 중복"이라는 규칙은 맞았지만, 의도된 사본이라는 맥락을 코드가 알 수 없었음
- 피해를 막은 요인: 반사적인 Ctrl+C, 우연히 남아있던 별도 백업 (모두 운이었음)
- 얻은 원칙: 삭제·이름변경처럼 되돌릴 수 없는 작업은 반드시 DRY_RUN(미리보기) 단계를 먼저 거친다
지금도 삭제나 이름 변경이 걸린 스크립트를 짤 때마다, 그날 터미널에 스쳐 지나가던 낯익은 파일명이 먼저 떠오릅니다. 그 덕분에 지금 이 블로그에 올라오는 모든 삭제·변경 관련 코드에는 예외 없이 미리보기 단계가 들어가 있습니다.
