bash_04 변수 내부 문자열을 n 번째부터 m 번째까지 추출하기

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

명령어: read, echo
키워드: 문자열, 일부, 추출
사용처: ID 목록 파일에서 지정한 ID 패턴만 추출하고 싶을 때


실행예제

$ ./bash-substr.sh id.lst
AC38421021 0
AC98102495 1

(ID 첫 문자가 "AC"인 것만 표시됨)

스크립트

#!/bin/bash

# 지정한 ID 파일에서 $id $status를 한 줄씩
# read 명령어로 읽어들임

while read id status  #------------------- 1
do
  # 셀 변수 id 첫 두 글자가 AC인지 확인
  if ["${id:0:2}" = "AC" ]; then  #------- 2(if문)
    echo "$id $status"
  fi
done < "$1"

   

해설

이 스크립트는 ID 목록 파일(id.lst)에서 AC로 시작하는 ID를 추출해서 ID와 스테이터스를 표시합니다. 여기서 이용하는 ID 목록 파일은 스페이스로 나눠서 “ID번호 스테이터스”처럼 기술한다고 가정합니다.

  • 파일1 ID 목록 파일(id.lst) 내용

    AC38421021 0
    HZ30281341 0
    DP92303190 1
    PX90909213 0
    AC98102495 1
    EE399r0900 1
    

ID 목록 처리는 셸 스크립트에서 자주 사용됩니다. 특히 ID 일부를 뽑아서 특정 문자열 패턴이 있는 ID만 추출하는 목록 처리는 응용 분야가 많을 것입니다.

앙케이트 대상이나 추첨 대상 ID 추출을 가정해서 ID 첫 부분이 AC로 시작하는 ID를 추출하는 예제입니다. 변수 내부의 문자열에서 지정한 n 번째 문자부터 m 개 만큼 뽑아내는 처리는 프로그래밍 언어에서는 substr 같은 함수를 사용합니다. 하지만 셸 스크립트는 substr 함수가 없으므로 스스로 처리해야 합니다. 이때 bash 파라미터 확장 기능을 이용합니다.

1은 while문에 명령행 인수로 지정한 파일($1)을 입력 리다이렉트합니다. 이걸 read 명령어로 한 줄씩 읽어서 셸 변수 id와 status 순서대로 대입해서 처리합니다.

2의 if문 조건식에서 셸 변수 id로 이용하는 것이 n 번째 문자부터 m 개 만큼 꺼내는 bash 파라미터 확장 표기법입니다. 이 기능은 다음처럼 이용합니다.

  • 파라미터 확장을 사용한 문자열 취득

    ${변수명:오프셋:문자수}
    ...[변수명]의 [오프셋] 위치에서부터 [문자수]만큼 취득
    
    ${변수명:오프셋}
    ...[변수명]의 [오프셋] 위치 뒤의 모든 문자열 취득
    

이때 offset은 0부터 세기 때문에 n번째 문자부터 취득할 때 실제로 지정하는 숫자는 n에서 1을 뺀 값이 됩니다.

다음 실행 예에서는 offset이 4이므로 셸 변수 str의 5번째 문자인 E에서 문자열을 취득합니다. ${str:4:2}라고 지정하면 두 글자를 취득하므로 EF가 되지만, ${str:4}라고 length를 생략하면 5번째 문자부터 마지막까지인 EFGHIJK를 취득합니다.

  • bash에서 파라미터 확장은 첫 위치가 0이 됨

    $ str="ABCDEFGHIJK"
    $ echo ${str:4:2}
    EF
    
    $ echo ${str:4}
    EFGHIJK
    

2에서 ${id:0:2}로 지정합니다. 이것은 ID의 첫 문자부터 두 글자를 취득한다는 의미입니다. 이것은 AC와 비교해서 일치할 때 그 ID 스테이터스를 echo 명령어로 표시합니다.

물론 이런 처리는 grep 명령어와 sed 명령어, cut 명령어를 사용해도 가능합니다. 하지만 bash 파라미터 확장을 이용하면 그런 외부 명령어를 사용하지 않아도 되고, 게다가 속도까지 빨라져 소개했습니다.

   

주의사항

  • 파라미터 확장 서식에서 offset이나 length는 산술 확장되므로 산술식을 그대로 작성할 수 있습니다. 따라서 다음처럼 몇 번째 문자부터 취득할지 셸 변수로 동적으로 지정할 수 있습니다.

    num=1
    
    # 취득할 오프셋값을 num+2로 지정
    echo ${id:num+2:2}
    

    또한 위의 예를 응용하면 변수 끝 한 글자만 추출하는 처리를 다음처럼 작성할 수 있습니다.

    echo ${id:${#id}-1}
    

    여기서 ${#id}는 셸 변수 id값의 문자열 길이입니다.