텍스트처리_15 정해진 자릿수 숫자에 하이픈 넣기(우편번호 등)

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

명령어: 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)’ 파일을 다룬다고 가정합니다. 구체적인 파일 내용은 실행 예제를 참조하기 바랍니다.

스크립트로 하이픈을 추가할 때는 다음과 같이 텍스트 파일을 다룹니다.

  1. 각 줄의 앞 뒤에 스페이스가 있으면 제거한다.
  2. 7자리 숫자가 아니라면 포맷 에러로 보고 무시한다.

한편, 하이픈을 삭제할 때는 다음과 같은 방법을 사용합니다.

  1. 각 줄의 앞 뒤에 스페이스가 있으면 제거한다.
  2. ‘3자리숫자-4자리숫자’가 아니라면 포맷 에러로 보고 무시한다.

이런 종류의 스크립트를 작성할 때면 ‘입력 텍스트 파일의 포맷에 맞지 않은 데이터를 어떻게 처리할까’ 라는 문제가 있는데 여기에서는 단순히 무시하도록 합니다.

우선 1에서 옵션 지정 플래그 변수  d_flag를 정의합니다. -d 옵션(하이픈 제거)이 지정되었는지 판별하는 변수입니다. 2getopts 명령어를 사용해서 실행할 때 -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-으로 치환하면 됩니다.

이렇게 하면 숫자 문자열을 가지고 우편번호 포맷 일치 확인과 하이픈 삭제 및 추가를 할 수 있습니다.

   

주의사항

  • 이 예제에서는 포맷과 일치하지 않는 에러를 무시하고 있지만 실제로 사용하려면 에러를 표시하거나 스크립트를 종료하는 등 상황에 따른 설계가 필요합니다.