bash_05 변수 내부 문자열 일부를 치환하기

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

명령어: echo
키워드: 파라미터 확장, 문자열, 치환, sed
사용처: 변수 내부 문자열을 sed 명령어를 사용하지 않고 치환하고 싶을 때


실행예제

$ ./bash-where.sh perl
/opt/local/bin/perl
/usr/bin/perl

스크립트

#!/bin/bash

# 조사할 명령어 얻기
command="$1"  #------------------------------------------ 1

# 인수 확인
if [ -z "$command" ]; then  #-----------------------------2(if문) 
  echo "에러: 조사 대상 명령어를 지정하세요." >&2
  exit 1
fi

# 환경 변수 $PATH의 :을 스페이스로 치환, for문 반복에서 사용
for dir in ${PATH//:/ }  #------------------------------- 3
do
  if [ -f "${dir}/${command}" ]; then
    echo "${dir}/${command}"
  fi
done

   

해설

이 스크립트는 명령행 인수로 지정한 명령어가 환경 변수 경로에 있는지 탐색해서 존재하면 그 경로를 나열합니다. 실행 예에서 perl 명령어로 /opt/local/bin과 /usr/bin 두 곳에서 발견했다는 걸 알 수 있습니다.

예제에서는 tcsh라는 셸의 where 명령어를 모방한 스크립트를 작성합니다. tcsh는 bash와 다른 계열의 C 셸 일종으로 BSD계 유닉스에서 자주 사용했습니다. tcsh에는 어떤 명령어가 경로 어디에 존재하는지 모두 나열하는 where라는 명령어가 있습니다.

bash는 where 명령어가 없기 때문에 스크립트로 작성해보겠습니다. 예를 들어 펄이 시스템에 다른 경로로 복수 개 설치되어 있으면 그 상태를 확인하기 위해 사용하는 툴로 편리하겠지요.

1에서 명령행 인수로 지정한 명령어를 위치 파라미터 $1에서 셸 변수 command에 대입합니다.

2는 그 인수 내용을 확인해서 빈 문자열인지 test 명령어 -z 옵션으로 확인합니다. 빈 문자열이면 명령어가 지정되어 있지 않으므로 에러를 표시하고 exit 명령어로 종료합니다.

3에서 bash 파라미터 확장 기능을 써서 :(콜론)을 스페이스로 치환합니다. 이런 문자열 치환은 일반적으로 sed 명령어를 사용하지만 bash에서는 표준 기능인 파라미터 확장으로 치환할 수 있어 외부 명령어인 sed를 사용하지 않아도 됩니다.

bash 파라미터 확장을 사용한 문자열 치환은 다음과 같은 서식을 이용합니다.

  • 파라미터 확장을 사용한 문자열 치환

    1. ${변수명/패턴/치환문자열}
    [변수명]의 마지막 일치한 [패턴]만 [치환문자열]로 바꿉니다. sed 명령어의 's/패턴/치환문자열/'에 해당합니다.
    
    2. ${변수명//패턴/치환문자열}
    [변수명]의 일치한 모든 [패턴]을 [치환문자열]로 바꿉니다. sed 명령어의 's/패턴/치환문자열/g'에 해당합니다.
    

패턴 지정은 와일드 카드인 *(임의 문자열)와 ?(임의 한 문자), 문자 클래스 지정[…] 등을 사용할 수 있습니다.

3에서 이용하는 변수 PATH는 명령어 경로 탐색을 지정하는 환경 변수로 다음처럼 콜론을 구분자로 지정합니다.

  • 환경 변수 PATH 설정 형식

    $ echo $PATH
    /usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin
    

콜론을 스페이스로 치환한 디렉터리 목록을 for문에 넘겨서 셸 변수 dir에 대입합니다. 각각의 경로에 명령행 인수로 지정한 명령어가 존재하는지 test 명령어 파일 확인 연산자 -f를 이용해서 확인하고 파일이 있으면 echo 명령어로 표시합니다.

이렇게 해서 명령어가 존재하는 모든 경로를 한 번에 표시할 수 있습니다. 같은 명령어가 여러 경로에 설치되어 있는지 확인하는 목적으로 사용할 수 있습니다.

   

주의사항

  • 이 스크립트는 for문에서 스페이스 구분자를 사용하므로 환경 변수 PATH에 스페이스를 포함한 디렉터리를 지정하면 제대로 동작하지 않습니다.

  • 파라미터 확장을 사용할 수 없는 sh 스크립트는 변수 내부 문자열을 치환할 때 다음처럼 echo 명령어로 변숫값을 출력해서 sed 명령어로 처리할 필요가 있습니다.

    echo $PATH | sed 's/:/ /g'
    
  • 문자열 치환 시 문자열 앞부분만 일치하는 /#이라는 표기법도 있습니다. 이것은 정규표현식에서는 ^로 표시하는 패턴입니다. 다음처럼 앞부분에 필요 없는 스페이스가 들어 있는 문자열과 없는 문자열이 있을 때 /#으로 치환하면 앞부분 스페이스가 있는 문자열은 치환되지 않습니다.

    # 앞부분에 필요 없는 스페이스가 있음
    str1=" http://www.example.com/"
    
    # 스페이스가 없음
    str2="http://www.example.com/"
    
    echo ${str1/#http:/hxxp:}
    echo ${str2/#http:/hxxp:}
    

    다음처럼 첫 번째 셸 변수 str1은 앞부분에 스페이스가 있어서 일치하지 않는다는 걸 알 수 있습니다.

    http://www.example.com/
    hxxp://www.example.com/
    

    그리고 이와는 반대로 끝부분에서 일치하고 싶을 때는 /% 표기법을 사용합니다.