변환 처리_11 미정의 변수를 에러로 처리해서 실수 방지하기

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

명령어: set
키워드: 미정의, 변수, 에러, 빈 문자열
사용처: 스크립트에서 정의 안 된 변수를 사용하면 에러 종료하고 싶을 때


실행예제

./set-u.sh
./set-u.sh: line 7: COP_DIR: unbound variable

스크립트

#!/bin/sh

set -u  #------- 1

COPY_DIR=/myapp/work

# COPY_DIR이 아니라 COP_DIR이라고 실수했다!
cp myapp.log $COP_DIR

   

해설

이 스크립트는 변수명을 잘못 타이핑해서 미정의 변수를 쓰게 될 때 에러를 표시하는 예제입니다. 실행하면 “unbound variable” 이라는 에러가 표시됩니다.

보통 셸 스크립트에서는 선언되지 않은 변수를 사용해도 에러가 발생하지 않습니다. 변수 대입은 변수 자체를 선언하지 않아도 가능하고, 미정의 변수를 참조하면 빈 문자열이 됩니다. 따라서 일일이 변수 선언을 하지 않아도 간단하게 프로그래밍이 가능하다는 점이 셸 스크립트 장점입니다.

하지만 변수 선언이 필요 없다는 셸 스크립트의 특징은 생각치 못한 버그를 만들 위험이 있습니다. 예를 들어 rm 명령어로 삭제할 경로명을 셸 변수로 지정할 때 조심해야 합니다.

[파일1]을 보기 바랍니다. 이것은 셸 변수 dirname으로 지정한 /mysapp/work/tmpdir 디렉터리를 삭제하는 스크립트 예입니다.

  • 파일1 셸 변수로 지정한 디렉터리 삭제하기

    #!/bin/sh
    
    dirname=/myapp/work/tmpdir
    rm -rf $dirname/
    

    하지만 이 스크립트는 만약 $dirname 부분을 실수해서 $dirnam 같이 작성해버리면 셸 변수 dirnam은 정의되지 않았으므로 빈 문자열이 되어 다음과 같이 실행됩니다.

    rm -rf /
    

위 명령은 /(루트 디렉터리)를 지우려는 시도이므로 시스템 전체가 파손되는 중대한 문제가 발생할 수도 있습니다. 이렇듯 변수명을 잘못 기입해서 해당 위치가 빈 문자열이 되어서 그 결과 생각하지 못한 파일을 삭제하는 일은 종종있는 버그로 치명적인 결과로 이어지기도 합니다.

이런 일을 방지하기 위해 1에서 set 명령어의 -u 옵션을 사용합니다. set -u를 지정하면 스크립트 내부에서 미정의 변수를 참조하려고 할 때 에러가 발생해서 셸 스크립트 실행이 중단됩니다. 미정의 변수를 사용하는 명령어의 실행을 막게 됩니다.

rm 명령어 같은 위험한 동작을 하는 셸 스크립트를 만들 때에는 set -u를 기본으로 설정해서 변수명이 정의되지 않으면 에러가 발생하도록 합시다.

##  set -u 부작용

set -u 부작용은 명령행 인수 $1 같은 걸 다루기 힘들어진다는 것입니다. 다음은 명령행 인수를 표시하는 단수한 스크립트입니다.

  • 파일2 명령행 인수를 표시하는 스크립트

    #!/bin/sh
    
    set -u
    
    echo "1st arg: $1"
    echo "2nd arg: $2"
    

    만약 set -u 옵션을 사용하지 않으면 지정되지 않은 명령행 인수는 참조 시 빈 문자열이 되므로 실행 결과는 이렇게 됩니다.

  • 인수가 하나뿐인 상황

    $ ./arg-set.sh 1
    1st arg: 1
    2nd arg:
    

    그러나 이 스크립트는 set -u가 있으므로 명령행 인수가 하나뿐이면 $2가 미정의 변수가 되어 다음과 같은 에러가 발생합니다. 이를 방지하려면 셸 스크립트 내부에서 명령행 인수가 몇 개인지 계산해서 처리해야 합니다.

    $ ./arg-set.sh 1
    1st arg: 1
    ./arg-set.sh: line 5: $2: unbound variable
    

    셸 스크립트에서 명령행 인수를 자주 다루므로 편리성을 위해 자주 set -u를 생략합니다. 뭐든지 set -u 처리를 한다고 좋은 것만은 아니므로 주의해야 합니다.