- 출처 : 유닉스 리눅스 쉘스크립트 예제사전_한빛미디어
명령어: getops, shift, awk, grep, sed
키워드: 옵션, 자릿수, 스페이스 제거, 우편번호
사용처: 우편번호나 전화번호 같은 텍스트에서 정해진 자리에 하이픈을 넣거나 삭제하고 싶을 때
실행예제
$ cat number-nohyphen.txt # 숫자뿐인 우편번호
5620001
2250022
A1200B1
$ ./num-hyphen.sh number-nohyphen.txt # 하이픈 추가
561-0001
225-0022
$ cat number-hyphen.txt # 하이픈이 있는 우편번호
562-0001
325-10022
362-0001
A1B-0C1C
$ ./number-hyphen.sh -d number-hyphen.txt # 하이픈 제거
5620001
3620001
스크립트
#!/bin/sh
# 하이픈을 삭제 여부 플래그. 1이면 삭제
d_flag=0 #-------------------------------------------- 1
# getopts 명령어로 삭제 옵션(-d) 판별
while getopts "d" option #---------------------------- 2
do
case $option in
d)
d_flag=1
;;
\?)
exit 1
;;
esac
done
# 명령행 인수로 지정한 우편번호 파일을
# 셸 변수 filename에 대입
shift $(expr $OPTIND - 1) #--------------------------- 3
filename="$1"
# 지정한 우편번호 파일 확인
if [ ! -f "$filename" ]; then #----------------------- 4(if문)
echo "대상파일이 존재하지 않습니다: $filename" >&2
exit 1
fi
# d_flag가 지정되면 하이픈 삭제. 아니면 하이픈 추가
if [ "$d_flag" -eq 1 ]; then #------------------------ 5
# 하이픈 삭제
# awk로 앞뒤 공백제거 -> 포맷 확인 -> 하이픈 삭제
awk '{print $1}' "$filename" | grep '^[0-9]\{3\}-[0-9]\{4\}$' | sed "s/-//" #-- 6
else
# 하이픈 추가
# awk로 앞뒤 공백 제거 -> 포맷 확인 -> 하이픈 추가
awk '{print %$1}' "$filename" | grep '^[0-9]\{7\}$' | sed "s/\(...\)/\1-/" #--- 7
fi
해설
이 스크립트는 7자리 숫자가 적힌 파일에서 3번째와 4번째 숫자 사이에 하이픈을 넣거나, 하이픈이 있는 7자리 숫자에서 하이픈을 삭제해서 표시합니다. 스크립트 옵션으로 -d를 지정하면 하이픈을 삭제하고 아니면 추가합니다. 우편번호를 비롯한 숫자 텍스트에 응용할 수 있습니다.
number-nohyphen.txt라는 하이픈이 없는 7자리 숫자(5620001 같은) 파일과 number-hyphen.txt라는 하이픈이 있는 ‘세 자리 숫자-네 자리 숫자(562-0001)’ 파일을 다룬다고 가정합니다. 구체적인 파일 내용은 실행 예제를 참조하기 바랍니다.
스크립트로 하이픈을 추가할 때는 다음과 같이 텍스트 파일을 다룹니다.
- 각 줄의 앞 뒤에 스페이스가 있으면 제거한다.
- 7자리 숫자가 아니라면 포맷 에러로 보고 무시한다.
한편, 하이픈을 삭제할 때는 다음과 같은 방법을 사용합니다.
- 각 줄의 앞 뒤에 스페이스가 있으면 제거한다.
- ‘3자리숫자-4자리숫자’가 아니라면 포맷 에러로 보고 무시한다.
이런 종류의 스크립트를 작성할 때면 ‘입력 텍스트 파일의 포맷에 맞지 않은 데이터를 어떻게 처리할까’ 라는 문제가 있는데 여기에서는 단순히 무시하도록 합니다.
우선 1
에서 옵션 지정 플래그 변수 d_flag를 정의합니다. -d 옵션(하이픈 제거)이 지정되었는지 판별하는 변수입니다. 2
는 getopts 명령어를 사용해서 실행할 때 -d 옵션이 지정되었는지 판별해서 지정했다면 1을 셸 변수 d_flag에 대입합니다.
3
은 우선 위치 파라미터에서 명령행 인수로 지정한 옵션을 shift 명령어로 당깁니다. 이러면 위치 파라미터 $1에 명령행 인수로 지정한 파일명이 저장되므로 $1을 셸 변수 filename에 대입합니다.
4
에서 지정한 우편번호 파일이 존재하는지 확인합니다. 부정 연산자 !와 일반 파일인지 확인하는 -f 연산자를 함께 써서 파일이 존재하지 않거나 디렉터리 등이라면 에러를 표시하고 종료합니다.
5
는 하이픈을 삭제할지 추가할지 if문으로 판단해서 분기합니다. -d 옵션이 지정되었으면 셸 변수 d_flag가 1이므로 하이픈을 삭제하는 6
처리로 분기합니다. -d 옵션 없다면 d_flag가 0이라서 if문은 거짓이 되고 하이픈을 추가하는 7
처리가 됩니다.
6
은 우선 앞뒤 스페이스를 제거하기 위해 awk 명령어로 첫 번째 컬럼을 {print $1}로 표시합니다. 텍스트 앞 뒤에 스페이스가 있다면 이렇게 해서 간단히 제거할 수 있습니다.
이어서 awk 명령어로 하이픈을 넣은 다음 grep 명령어로 포맷을 확인합니다. 여기에서 {3}을 사용합니다. 이것은 패턴이 몇 번 출현하는지 나타내는 정규표현식으로 {}으로 싼 숫자 횟수만큼 직전 문자가 반복해서 나올 때 일치하게 됩니다.
grep 'e\{2\}' -----------> ee와 일치, grep "ee"와 동일
grep '[a-zA-Z]\{8\}' ---> 영문자 8글자
여기에서 우선 [0-9]로 숫자를 의미하는 문자 클래스를 지정하고, 그 뒤에 {3}이라고 세번 나오는 패턴을 하이픈으로 이어서 [0-9]{3}-[0-9]{4}를 사용합니다. 이것은 ‘세 자리 숫자 뒤에 하이픈이 나오고 다시 네 자리 숫자가 옴’이란 패턴입니다. 여기에 일치하지 않는 줄은 포맷 에러이므로 표시하지 않도록 무시합니다.
6
마지막에 sed 명령어로 하이픈을 삭제합니다. sed 명령어로 문자를 삭제하려면 캐릭터를 지정해서 빈 문자열로 치환하면 되므로 “s/-//”라고 적으면 하이픈을 제거할 수 있습니다.
-d 옵션을 지정하지 않으면 7
처리로 분기합니다. 여기서는 하이픈을 추가하는 처리를 합니다. 6
처럼 앞뒤 스페이스를 제거하기 위해 awk 명령어로 {printf $1}을 한다음, [0-9]{7}라는 포맷과 일치하는지 확인하는 grep 명령어를 실행합니다. 7자리 숫자가 등장하지 않으면 무시하게 됩니다.
7
마지막에 sed 명령어로 하이픈을 추가합니다. 여기에는 7자리 숫자 문자열이 넘어오므로 “앞에서부터 세자리 뒤에 하이픈을 추가”라는 처리를 하기 위해 우선 앞 세 자리를 (…)로 지정하여 후방참조가 가능하도록 합니다. 그런 다음 하이픈을 추가하면 되므로 치환 후 문자열은 후방참조 \1을 사용해서 \1-으로 치환하면 됩니다.
이렇게 하면 숫자 문자열을 가지고 우편번호 포맷 일치 확인과 하이픈 삭제 및 추가를 할 수 있습니다.
주의사항
- 이 예제에서는 포맷과 일치하지 않는 에러를 무시하고 있지만 실제로 사용하려면 에러를 표시하거나 스크립트를 종료하는 등 상황에 따른 설계가 필요합니다.