파일처리_22 두 디렉터리를 비교해서 한 쪽에만 있는 파일 표시하기

 
  • 출처 : 유닉스 리눅스 쉘스크립트 예제사전_한빛미디어

명령어: find, sort, comm
키워드: 파일 목록, 디렉터리 비교
사용처: 두 디렉터리가 비슷한 구조일 대 한쪽에만 있거나 양쪽에 있는 파일을 보기 좋게 목록화하고 싶을 때


실행예제

$ ./find-comm.sh
./dav.conf
                ./default.conf
                ./info.conf
                ./mpm.conf
      ./ssl.conf
                ./userdir.conf
./vhosts.conf

스크립트

#!/bin/sh

# 비교할 디렉터리명
dirA="dir1"
dirB="dir2"

# dir1/과 dir2/ 파일 목록 차이를 조사하기
( cd dir1; find . -maxdepth 1 -type f -print | sort ) > dir1-file.lst  #--- 1
( cd dir2; find . -maxdepth 1 -type f -print | sort ) > dir2-file.lst  #--- 1
 
comm dir1-file.lst dir2-file.lst  #---------------------------------------- 2

   

해설

이 스크립트는 현재 디렉터리 아래이 있는 dir1과 dir2 디렉터리의 파일을 조사해서 아래에 조건에 맞게 나눠서 출력합니다.

  1. dir1에만 있는 파일
  2. dir2에만 있는 파일
  3. dir과 dir2 양쪽에 있는 파일

을 나눠서 출력합니다. 출력은 탭으로 정렬해서 1, 2, 3 순서대로 표시됩니다. 실행 예제에서는 dav.conf와 vhosts.conf가 디렉터리 dir1에만 있고 ssl.conf는 dir2에만 있고, 나머지 파일은 양쪽 디렉터리에 존재합니다. 실제로 이 예제를 실행할 때는 셸 변수 dirA와 dirB를 비교하고 싶은 디렉터리로 변경하기 바랍니다.

1에서 각각 서브 디렉터리마다 파일 목록을 임시 파일에 출력합니다. 여기에서는 디렉터리 이동과 리다이렉트 출력 모두를 서브셸에서 합니다. 서브셸을 쓰는 것은 cd 명령어로 현재 디렉터리를 이동하고 나서 원래 디렉터리로 자동으로 돌아오기 위해서입니다.

우선 1에서는 디렉터리 파일 목록을 만들 때 find 명령어-type f를 지정해서 디렉터리를 제외하고 보통 파일만 지정합니다. 그리고 -maxdepth 1로 두 단계 이상 깊은 디렉터리 안에 있는 파일을 제외하고 서브 디렉터리 바로 아래 있는 파일만 대상으로 삼습니다.

디렉터리 dir1 파일 목록을 tempfile1.lst로, 디렉터리 dir2 파일 목록을 tempfile2.lst로 출력했으므로 이 파일을 비교합니다.

2에서 comm 명령어로 두 디렉터리 파일 목록 차분을 출력합니다. comm 명령어는 파일 내용을 비교하는 명령어도 두 입력 파일을 읽어서 같은 줄과 다른 줄을 각각 표시합니다. comm 명령어 실행 예제 결과는 아래와 같습니다.

  • comm 명령어는 두 파일을 비교함
    $ comm file1 file2
                   1
    2
          3
                   4
                   5
                   6
    7
    

여기서 각 열의 의미는 다음과 같습니다.

  • 첫 열은 file1 에만 있는 행 출력
  • 두 번재 열은 file2에만 있는 행 출력
  • 세 번째 열은 양쪽에 공통된 행 출력

그리고 comm 명령어를 사용할 때는 입력 파일이 정렬되어 있어야 합니다. 따라서 예제에서는 1에서 find를 실행한 다음 sort 명령어로 정렬하고, 임시 파일에 출력합니다. 이렇게 디렉터리 파일 목록을 comm 명령어로 비교해서 각 디렉터리에 있는 파일을 비교합니다.

   

주의사항

  • 이렇게 두 디렉터리 사이에 파일 목록 차이를 확인한 다음 디렉터리끼리 파일을 동기화하고 싶을 때가 있습니다. 두 디렉터리 간 파일을 동기화하려면 rsync 명령어가 편리합니다.

  • comm 명령어는 지정한 열만 출력할 수도 있습니다. 이때 표시하고 싶은 열을 -1 또는 -2처럼 지정합니다. 양족 파일에 존재하는 줄만 표시하고 싶다면 다음처럼 -12로 세 번째 열만 표시하면 됩니다.
    comm -12 file1 file2
    
  • comm 명령어 종료 스테이터스는 diff 명령어와 약간 다르므로 주의해야 합니다. diff 명령어 종료 스테이터스는 다음과 같습니다.

    • 두 파일이 동일하면 종료 스테이터스는 0
    • 두 파일에 차이가 있으면 1
    • 파일이 없거나 에러 발생 시 2
  • 즉 diff 명령어는 종료 스테이터스가 0 또는 1일 때 두 파일에 차이가 있는지 없는지 판단하는 것이 일반적입니다.

  • 한편, comm 명령어는 두 파일의 차이가 있든지 없든지 정상 종료라면 종료 스테이터스로 0을 돌려줍니다. comm 명령어가 종료 스테이터스로 0이 아닌 값을 돌려주면 파일이 발견되지 않는 등 에러가 발생했을 때 뿐입니다. 따라서 comm 명령어 종료 스테이터스를 확인해서 조건 분기로 스크립트를 만들 때는 diff 명령어와 다르다는 사실에 유의하기 바랍니다.