본문 바로가기
TYLER SONGBlog
← Blog index
CS학습4 min read

mv: 파일 이동과 이름 변경을 하나의 명령으로 처리하는 방법

mv는 파일이나 디렉터리를 다른 경로로 옮기거나 이름을 바꾸는 리눅스 명령이다. 같은 파일시스템 안에서는 데이터 복사 없이 디렉터리 항목(directory entry)만 수정하므로 크기와 무관하게 빠르게 끝난다. 파일시스템이 다르면 복사 후 삭제로 동작하며, 덮어쓰기 위험이 있어 -i, -n 같은 옵션을 알아두어야 한다.

By 송민성

1. 개념

mv(move)는 파일 또는 디렉터리의 경로를 바꾸는 명령이다. 이동과 이름 변경을 구분하지 않고 "원본 경로를 대상 경로로 바꾼다"는 하나의 동작으로 처리한다.

shell
mv 원본 대상 mv 원본1 원본2 ... 대상디렉터리/
  • 대상이 존재하는 디렉터리면 그 안으로 이동한다.
  • 대상이 존재하지 않는 경로면 그 이름으로 바뀐다.
  • 대상이 존재하는 파일이면 기본적으로 덮어쓴다.

2. 왜 사용하는가

  • 파일 정리, 배포 디렉터리 교체, 로그 로테이션 같은 작업에서 파일 위치를 바꿔야 한다.
  • 같은 파일시스템 안에서는 cp 후 rm보다 빠르고 안전하다. 데이터 블록을 복사하지 않기 때문이다.
  • 같은 파일시스템 안의 이동은 원자적(atomic) 연산이라, 파일 교체 시 중간 상태를 노출하지 않는다.

3. 동작 원리

리눅스 파일시스템에서 파일 이름은 디렉터리 항목(directory entry)이 inode 번호를 가리키는 형태로 저장된다. 파일의 실제 데이터와 메타데이터는 inode에 있다.

같은 파일시스템 내 이동

mv는 rename(2) 시스템 콜을 호출한다. 원본 디렉터리에서 항목을 제거하고 대상 디렉터리에 같은 inode를 가리키는 항목을 추가할 뿐, 데이터 블록은 건드리지 않는다. 그래서 파일 크기와 관계없이 inode 번호도 그대로 유지된다.

다른 파일시스템 간 이동

rename(2)은 파일시스템 경계를 넘을 수 없어 EXDEV 오류를 반환한다. 이때 mv는 대상에 복사한 뒤 원본을 삭제하는 방식으로 대체한다. 새 파일시스템에서는 새 inode가 할당된다.

4. 코드 예제

실습용 디렉터리에서 실행할 수 있는 예제다.

shell
mkdir -p /tmp/mv_demo/archive && cd /tmp/mv_demo echo "hello" > a.txt # 1) 이름 변경 mv a.txt b.txt # 2) 디렉터리로 이동 mv b.txt archive/ # 3) 여러 파일을 한 번에 이동 touch x.log y.log mv x.log y.log archive/ # 4) 덮어쓰기 방지 echo "new" > c.txt echo "old" > archive/c.txt mv -i c.txt archive/ # 덮어쓸지 질문 mv -n c.txt archive/ # 존재하면 이동하지 않음 # 5) 이동 과정 출력 mv -v c.txt archive/d.txt # 6) inode 유지 확인 (같은 파일시스템) touch f.txt ls -i f.txt mv f.txt g.txt ls -i g.txt # 동일한 inode 번호

주요 옵션은 다음과 같다.

옵션의미
-i덮어쓰기 전 확인
-n기존 파일을 덮어쓰지 않음
-f확인 없이 덮어씀
-v수행 내용을 출력
-t DIR대상 디렉터리를 먼저 지정 (GNU mv)
-b덮어쓰기 전 백업 생성 (GNU mv)

5. 시간 복잡도 또는 성능 특성

  • 같은 파일시스템: 디렉터리 항목만 수정하므로 파일 크기와 무관하다. 데이터 복사가 없다는 점이 핵심이며, 정확한 시간은 파일시스템 구현에 따라 다르다.
  • 다른 파일시스템: 복사가 필요하므로 소요 시간이 데이터 크기에 비례한다(O(n), n은 바이트 수).
  • 디렉터리를 이동할 때도 같은 파일시스템이면 하위 파일을 개별 처리하지 않고 디렉터리 항목만 옮긴다.

6. 실무 사용 사례

  • 배포 교체: 새 버전을 임시 경로에 올린 뒤 mv로 교체하면 같은 파일시스템 안에서는 중간 상태 없이 전환된다.
  • 원자적 파일 쓰기: 설정 파일을 임시 파일에 쓴 뒤 mv로 덮어써서, 읽는 쪽이 반쯤 쓰인 파일을 보지 않게 한다.
  • 로그 로테이션: mv app.log app.log.1 후 새 로그 파일을 생성한다.
  • 일괄 정리: find와 조합해 조건에 맞는 파일을 한꺼번에 옮긴다.
shell
# 원자적 교체 예: 같은 디렉터리에 임시 파일을 만들어야 같은 파일시스템이 보장된다 echo "port=8080" > config.tmp mv config.tmp config.conf # 30일 이상 지난 .log 파일을 archive로 이동 find . -maxdepth 1 -name "*.log" -mtime +30 -exec mv -t archive/ {} +

7. 주의할 점

  • 기본 덮어쓰기: 대상에 같은 이름의 파일이 있으면 경고 없이 덮어쓴다. 중요한 경로에서는 -i나 -n을 쓴다.
  • 끝의 슬래시와 존재 여부: mv a dir에서 dir이 없으면 a의 이름이 dir로 바뀐다. 의도가 디렉터리 이동이면 mv a dir/처럼 쓰면 dir이 없을 때 오류가 나서 실수를 막아준다.
  • 와일드카드: mv * dest/는 dest 자신도 대상에 포함하려다 오류를 낼 수 있고, 숨김 파일(.으로 시작)은 *에 포함되지 않는다.
  • `-` 로 시작하는 파일명: mv -- -weird.txt ok.txt처럼 --로 옵션 종료를 알린다.
  • 파일시스템 경계: 다른 파일시스템으로의 이동은 원자적이지 않다. 도중에 중단되면 원본과 복사본이 모두 남거나 일부만 복사될 수 있다.
  • 복구 불가: 덮어쓴 파일은 휴지통 없이 사라진다.

8. 핵심 정리

  • mv는 이동과 이름 변경을 같은 방식으로 처리한다.
  • 같은 파일시스템에서는 rename(2)으로 디렉터리 항목만 바꾸므로 빠르고 원자적이며 inode가 유지된다.
  • 다른 파일시스템으로 옮기면 복사 후 삭제로 동작해 크기에 비례하는 시간이 들고 원자성이 없다.
  • 기본값은 덮어쓰기이므로 -i, -n을 습관적으로 활용한다.
  • 임시 파일을 같은 디렉터리에 만든 뒤 mv로 교체하는 패턴은 안전한 파일 갱신의 기본이다.