리눅스 mv 명령어 사용법 - 파일 이동·이름 변경과 덮어쓰기 주의점
이 명령어를 언제 쓰는가
mv는 파일·디렉토리의 이름을 바꾸거나 다른 위치로 옮긴다. 실무에서는 두 가지 용도가 압도적이다. 하나는 배포 시 새 버전으로 바꿔치기, 다른 하나는 지우기 전 대기 장소로 치워 두기다.
같은 파일시스템 안에서 mv는 데이터를 복사하지 않는다. 디렉토리 엔트리만 바꾸므로 100GB 파일도 즉시 끝나고, 그 과정에서 다른 프로세스가 중간 상태를 보는 일이 없다. 이 성질(원자적 교체) 때문에 설정 파일 반영에 cp 대신 mv를 쓴다.
기본 형식
mv [옵션] 원본 [원본 ...] 대상
대상이 존재하는 디렉토리면 그 안으로 옮기고, 아니면 그 이름으로 바꾼다. 원본이 여러 개면 대상은 반드시 디렉토리여야 한다.
자주 쓰는 옵션
| 옵션 | 의미 | 예시 |
|---|---|---|
| -i | 덮어쓰기 전에 확인 | mv -i new.conf /etc/app.conf |
| -n | 대상이 있으면 덮어쓰지 않고 건너뛴다 | mv -n *.log /archive/ |
| -f | 확인 없이 덮어쓴다(기본 동작이지만 alias를 무시할 때 명시) | mv -f a b |
| -v | 옮긴 결과를 출력 | mv -v old new |
| -t 디렉토리 | 대상을 먼저 지정(xargs와 조합할 때 필수, GNU) | ... | xargs mv -t /archive/ |
| -u | 원본이 더 새로울 때만 옮긴다 | mv -u *.dat /data/ |
| --backup=numbered | 덮어쓸 대상을 번호 붙여 남긴다(GNU) | mv --backup=numbered new.conf /etc/app.conf |
실전 예제
1) 설정 파일을 원자적으로 교체 — 임시 파일에 다 쓴 뒤 마지막에 mv로 갈아끼운다. 이렇게 하면 반쯤 쓰인 설정을 데몬이 읽는 사고가 없다.
cp -p /etc/myapp/app.conf /etc/myapp/app.conf.bak
vi /etc/myapp/app.conf.new
mv /etc/myapp/app.conf.new /etc/myapp/app.conf
systemctl reload myapp
임시 파일은 반드시 대상과 같은 파일시스템에 만들어야 원자성이 보장된다.
2) 지우기 전에 치워 두기 — 바로 rm하지 않고 며칠 두면 되돌릴 수 있다.
mkdir -p /var/tmp/trash/20260825
mv /opt/app/releases/20260701T1030 /var/tmp/trash/20260825/
3) 확장자를 한꺼번에 바꾸기 — 셸 루프로 처리한다. mv *.txt *.bak은 동작하지 않는다.
for f in *.txt; do
mv -- "$f" "${f%.txt}.bak"
done
4) 대시로 시작하는 파일 옮기기 — 옵션으로 해석되는 것을 막는다.
mv -- -report.csv /data/reports/
5) 파일이 아주 많을 때 — 인자 길이 제한을 피하고, 대상을 -t로 먼저 준다.
find /var/log/myapp -maxdepth 1 -name '*.log.1' -print0 \
| xargs -0 -r mv -t /archive/20260825/
함정과 주의점
서비스가 쓰고 있는 로그 파일을 mv하면 로그가 사라진 것처럼 보인다. 프로세스는 파일명이 아니라 열어 둔 파일 디스크립터(아이노드)에 쓰기 때문에, 이름을 바꿔도 계속 옮겨진 파일에 기록한다. 새 이름의 빈 로그는 영원히 0바이트다. 반드시 로테이션 후 프로세스에 재오픈 신호를 보내거나(systemctl reload, kill -USR1), logrotate의 copytruncate를 쓴다.
파일시스템을 넘는 mv는 복사 후 삭제라 즉시 끝나지 않는다. /data와 /backup이 다른 마운트라면 실제로는 전체 복사가 일어나고, 중간에 세션이 끊기면 원본과 사본이 반쯤 남는다. 마운트가 다른지는 df /data /backup로 확인하고, 대용량이면 rsync 후 검증하고 지우는 절차로 나눈다.
대상 디렉토리 존재 여부로 결과가 달라진다. mv dir1 dir2는 dir2가 없으면 이름 변경, 있으면 dir2/dir1로 들어간다. 배포 스크립트에서 이 차이 때문에 /opt/app/app 같은 구조가 생긴다. 이름 변경 의도라면 대상이 없는지 먼저 확인한다.
[ -e /opt/app/current ] && echo "이미 존재함" || mv /opt/app/new /opt/app/current
mv는 기본적으로 묻지 않고 덮어쓴다. 게다가 덮어쓴 파일은 복구할 수 없다. 배포 스크립트에서는 -n이나 --backup=numbered를, 손으로 칠 때는 -i를 쓴다. 다만 배포판 기본 alias(alias mv='mv -i')에 기대면 cron이나 다른 계정에서는 동작하지 않는다.
함께 보면 좋은 명령어
- cp — 원본을 남겨야 할 때. 백업을 만들고
mv로 교체하는 조합을 자주 쓴다. - rename — 여러 파일 이름을 규칙으로 한 번에 바꾼다(배포판에 따라
rename/perl-rename). - logrotate — 로그 파일 이동은 손으로 하지 말고 로테이션 설정으로 맡긴다.