파일처리_25 .svn 등 숨은 파일과 디렉터리만 나열하기

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

명령어: ls, case
키워드: 숨김 파일, 닷 파일
사용처: 숨김 파일만 대상으로 처리하고 싶을 때


실행예제

$ ./dotfile.sh
dot file: .bashrc
dot fiel: .cshrc
dot directory: .svn/

스크립트

#!/bin/sh

# IFS에 줄바꿈 설정
IFS='
' #----------------------------------------- 1

# 현재 디렉터리 아래에 있는 파일을 $filename으로 순서대로 처리
for filename in $(ls -AF) #----------------- 2
do
    case "$filename" in #------------------- 3
    .*/)
        echo "dot directory: $filename"
    ;;
    .*)
        echo "dot file: $filename"
    ;;
    esac
done

   

해설

이 스크립트는 현재 디렉터리에 있는 닷 파일(디렉터리)을 각각 파일인지 디렉터리인지 표시하여 열거합니다.

유닉스에서는 파일명 처음이 .(닷)이면 닷 파일이라고 부르며 숨김 파일로 다룹니다. 닷 파일은 명령어 설정 등 특수 용도로 사용하는 일이 많고 특별하게 다루기도 하므로 이 예제처럼 닷 파일만 대상으로 하는 스크립트도 필요할 때가 있습니다. 자주 쓰는 닷 파일을 표로 정리해 보았습니다.

  • 자주 쓰는 닷 파일(디렉터리)
이름 용도
.bash_profile bash 로그인 시 읽어들이는 환경 설정 파일
.mysql_history mysql 멸영어 실행 이력 파일
.vimrc vi(vim) 에디터 환경 설정 파일
.DS_Store 파인더가 사용하는 폴더 정보 파일(Mac용)
.ssh(디렉터리) ssh 접속용 키 파일 등을 저장. 비밀키를 포함하고 있으므로 주의가 필요
.svn(디렉터리) 서브 버전 작업 복사 관리 디렉터리
.git(디렉터리) Git 리포지터리 관리 디렉터리

이 스크립트는 닷 파일 목록을 ls 명령어로 작성하는데 사전 준비로 1에서 IFS 변수를 변경합니다. 1은 문장 도중에 줄바꿈이 있어서 잘못되어 보이지만 정상입니다.

IFS란 Internal Field Separator 약어로 셸이 사용하는 구분자로 해석하는 문자를 설정하는 특수 변수입니다. 기본값으로 줄바꿈, 탭, 스페이스가 설정됩니다. 1은 이 IFS에 줄바꿈만 대입합니다. 이후 스크립트에서는 셸 구분자로 줄바꿈만 사용하고 스페이스와 탭은 사용하지 않기 위한 처리입니다.

이 예제에서는 파일명을 다루므로 파일명에 스페이스가 포함될 때마다 문자열로 다루는 불편함이 없도록 IFS로 줄바꿈만 설정해서 스페이스를 제외합니다. 변수 대입이 1처럼 두 줄로 나뉘는 것은 다른 언어에서는 자주 볼 수 없는 형태이지만 셸 스크립트 IFS 설정에서는 비교적 자주 사용되는 방법입니다.

그럼 닷 파일은 ls 명령어를 쓰면 간단히 목록을 얻을 수 있을 것 같지만 단순히 *(애스터리스크)를 써서 ls * 하면 닷 파일은 대상에서 제외됩니다. 이것은 셸 사양에서 닷 파일을 *에 포함하지 않기 때문입니다.

ls 명령어 와일드 카드 지정으로 닷 파일을 얻으려면 .* 처럼 “닷 + 와일드카드”를 명시적으로 지정하는 방법이 있습니다. 하지만 현재 디렉터리를 의미하는 .과 부모 디렉터리를 의미하는 ..도 대상이 됩니다.

따라서 2에서 ls 명령어 -A 옵션으로 닷 파일을 포함한 현재 디렉터리의 모든 파일을 표시하고 case 문으로 분류하는 방법으로 닷 파일만 추출합니다. ls -A라면 현재 디렉터리와 부모 디렉터리를 표시하지 않으므로 첫 문자가 .인지 아닌지라는 단순한 판별로 닷 파일을 추출할 수 있습니다.

그리고 2에서는 파일인지 디렉터리인지 구별하기 위해 ls 명령어 -F 옵션도 함께 사용합니다. -F 옵션을 쓰면 디렉터리 마지막에 /를 붙이므로 이것을 보고 디렉터리인지 판단할 수 있습니다.

실제로 파일과 디렉터리를 판단하는 것은 3 case 문입니다. 셸 스크립트에서 문자열 일치로 처리 분기하고 싶을 때는 이런 case 문을 사용하면 간단합니다. 파일명이 .으로 시작해서 /로 끝나면 (.*/) 디렉터리로 보고 “dot directory”를 표시하고, 그 위에 .으로 시작하면 (.*) 파일로 보고 “dot file”을 표시합니다.

   

주의사항

  • 1에서 변경한 IFS 변수는 그대로 두면 다른 처리에서 부작용이 발생할 수 있으므로 변경하기 전 값을 저장해두고 사용이 끝나면 원래 값으로 돌려두는 것이 좋습니다.
IFS_BACKUP=$IFS
IFS='
'

# (어떤 처리를 실행)

IFS=$IFS_BACKUP
  • IFS에 줄바꿈을 지정하는 다른 방법입니다. 이쪽이 줄바꿈이라는 걸 이해하기 쉽지만 POSIX 표준이 아니므로 우분투 sh 등 일부 환경에서는 제대로 동작하지 않습니다.
IFS=$'\n'