Shell script 제어문 분석

Halim Kim·2021년 12월 3일
0

Shell Script

목록 보기
2/2

작성계기

Shell Script를 공부하다가 반복문이나 조건문 같은 제어문의 사용이 다른 언어에 비해 복잡하다는 것을 느꼈다. 그래서 공부를 해도 조금씩 헷갈리기에 한번 정리하여 글로 남겨보려고 이번 포스팅을 작성하였다.

주로 다른 언어 특성과 비교하면서 Shell Script에서 유념해야 할 부분에 대해서 정리를 해보았다.

아래에 C/C++과 Bash Shell script 비교 예시 코드를 가져왔고 두 코드 모두 변수 x에 대해서 x가 1보다 작다면 "ok"를 출력하는 코드이다.


// C/C++ 에서의 조건문
int x = 0;
if( x < 1 )
	cout<<"ok"<<endl;

# Bash Shell에서의 조건문
x=0
if [ $x -lt 1 ]
then
	echo "ok"
fi

분석

위의 코드를 보고 눈여겨 보아야 하는 점들을 아래에 기록을 해놓았다.

① if 다음에 오는 괄호

다른 언어에서와 달리 Shell Script에서는 if문의 첫번째 괄호에 반드시 띄어쓰기가 들어가야 한다. 띄어쓰기가 없으면 문법적으로 오류가 생기기 때문에 주의해야 한다. "if"라는 제어명령을 쓴 후에 띄어쓰기를 한번 하고 시작괄호를 넣고 그 다음 한번 더 띄어쓰기를 해주어야 한다.

if [ $x -lt 1 ] # 정상
if[ $x -lt 1 ] # 에러 
if [$x -lt 1 ] # 에러

② 부등호 표시 대신 -lt

영어에 익숙하신 분들은 직감적으로 "lt""less than"을 의미한다는 것을 눈치챘을 것이다. 그래서 사람에 따라서 부등호 표시보다 이렇게 영어 소문자로 비교를 하는 것이 더 편할 수도 있다. 그리고 "작다"는 표현이 "-lt"이니까 "크다"는 표현은 "-gt" 라는 것을 유추해낼 수 있다. 아래는 모든 비교표현에 대해 정리한 표이다.

비교 표현비교 표현 기호비교 표현
x가 y보다 작다x < yx -lt y
x가 y보다 크다x > yx -gt y
x가 y보다 작거나 같다x <= yx -le y
x가 y보다 크거나 같다x >= yx -ge y
x가 y와 같다x == yx -eq y
x가 y와 같지 않다x != yx -ne y

개인적으로 정수를 비교할 때는 영어로된 약자를 쓰기보다는 부등호를 사용하는 것이 편하다고 느낀다. 그러나 파일을 테스트할 때는 영어로된 약자를 사용하는 것이 직관적이다. 예를 들면 아래와 같다.

if [ -f /root/dir/file1 ] # /root/dir에 file1이라는 파일이 존재하는지 아닌지 확인
if [ -d /root/dir/dir1 ] # /root/dir에 존재하는 dir1이 디렉터리인지 아닌지 확인
# 그 외..

③ 영어 약자 대신 부등호를 쓰고 싶다면?

첫 번째 방법

다행히도 제어문에서 비교를 할 때 무조건 영어로된 비교 표현을 써야 하는 것은 아니다. Bash의 2점대 버전 이후로 더블 브라켓( "[[ ]]" )을 사용하면 C/C++에서 제어문을 사용할 때처럼 비교 표현 기호를 사용할 수 있다.

두 번째 방법

추가로 "let"이라는 쉘 빌트인 명령을 사용하는 방법도 있다. let 명령어는 산술 표현식을 평가하는 명령이며 소괄호 2개( "(( ))" )를 활용해서 사용할 수 있다. 아래는 man page에서 let 명령어에 대한 설명을 가져온 부분이다.

let 명령어 man page
let arg [arg ...]
Each arg is an arithmetic expression to be evaluated (see ARITHMETIC EVALUATION above). If the last arg evaluates to 0, let returns 1; 0 is returned otherwise.

그래서 아래의 조건문은 모두 같은 의미를 가진다.

if [ $x -lt 1 ] 
if [[ $x < 1 ]] # Bash version 2.x 이후부터 지원
if (( $x < 1 )) # let 명령어 활용

④ 표현식이 반환하는 값

C/C++에서는 아래의 표현식이 비교 결과에 따라서 Bool값의 true(1) 혹은 false(0)을 반환한다.

if( x < 1 )

그러나 Shell Script에서는 반대이다. Shell Script는 정수형 값을 이용하는데 0이면 true이고 그 이외의 숫자들은 false로 인식한다. 그리고 exit 값을 이용한다.

exit 값은 exit라는 명령어와 함께 사용된 아규먼트 값을 말한다. 누군가 작성해놓은 Shell Script를 보면 예외 처리를 하면서 exit 1, exit 3 이런식으로 사용된 것을 볼 수 있을텐데 여기서 1과 3이 exit 값이다. (예외 처리에서는 exit 명령어의 아규먼트로 0이 아닌 숫자를 이용한다. 그러니까 이 값을 통해 실행이 잘 되었는지 아닌지 확인할 수 있는 것이다.)

참고! exit 값은 Shell의 예약 변수로도 저장이 되어 있다. ?라는 변수에 exit 값이 저장되어 있으니 "echo $?"라고 명령어를 입력해 엔터를 누르면 확인할 수 있다. 이전 명령어가 정상적으로 실행되었다면 0을 출력하고 그렇지 못하다면 그 이외의 숫자를 출력할 것이다.

지금까지 예시로 들었던 if문에서도 exit 값을 반환하는 부분이 있다. "[ ]"와 "[[ ]]"는 "test"라는 쉘 빌트인 명령을 내부적으로 사용하여 exit 값을 반환하는 것이고 "(( ))"는 위에서 설명했듯이 "let"이라는 쉘 빌트인 명령을 사용한 것이다.

exit 값을 이용한다는 사실을 기억해야 하는 이유를 코드로 설명을 해보겠다. 이번에는 if문이 아니라 while문을 사용했는데 조건식을 사용하는 방법은 똑같다.

x=1
while [ $x ]
do
	echo $?
   	sleep 5
done

x 변수에 0이 아닌 1을 대입했기 때문에 while문이 동작하지 않을 것이라고 생각할 수도 있지만 while문은 계속 반복하여 실행이 될 것이고 지속해서 0이 출력될 것이다.

그 이유는 일단 기본적으로 Shell Script에서 변수는 정수형이 아니라 문자열로 인식되어 저장된다. 그러니까 x에는 "1"이라는 문자열이 들어가 있는 상태인 것이다. 그리고 while문 옆에서 test라는 쉘 빌트인 명령을 사용하는데 아규먼트는 변수 x, 즉 문자열 "1"인 것이다. 그런데 test 명령어는 단순한 문자열 아규먼트에 대해서는 exit 값으로 0을 반환한다. 그러니까 while문이 반복해서 실행되는 것이다.

마찬가지로 아래의 코드도 반복문이 계속해서 실행된다.

while [ 1 ]
do
	echo $?
   	sleep 5
done

다만 이는 대괄호 안의 값이 true로 인식되어서가 아니라 test 명령에 의한 exit값이 계속해서 0이기 때문이다. 그래서 대괄호 안의 값이 0이어도 계속 실행되기 때문에 Shell Script를 작성할 때 주의해야 한다.

profile
나는 하림

0개의 댓글