7.1. 테스트(Test Constructs)

예 7-1. 무엇이 참인가?

#!/bin/bash

echo

echo "\"0\" 테스트"
if [ 0 ]      # zero
then
  echo "0 은 참."
else
  echo "0 은 거짓."
fi

echo

echo "\"NULL\" 테스트"
if [ ]        # NULL (empty condition)
then
  echo "NULL 은 참."
else
  echo "NULL 은 거짓."
fi

echo

echo "\"xyz\" 테스트"
if [ xyz ]    # 문자열
then
  echo "임의의 문자열은 참."
else
  echo "임의의 문자열은 거짓."
fi

echo

echo "\"\$xyz\" 테스트"
if [ $xyz ]   # $xyz 가 널인지 테스트...
              # 하지만 단지 초기화되지 않은 변수일 때만.
then
  echo "초기화 안 된 변수는 참."
else
  echo "초기화 안 된 변수는 거짓."
fi

echo

echo "\"-n \$xyz\" 테스트"
if [ -n "$xyz" ]            # 좀 더 어렵게 보이게.
then
  echo "초기화 안 된 변수는 참."
else
  echo "초기화 안 된 변수는 거짓."
fi

echo

xyz=                        # 널 값으로 초기화.

echo "\"-n \$xyz\" 테스트"
if [ -n "$xyz" ]
then
  echo "널 변수는 참."
else
  echo "널 변수는 거짓."
fi


echo


# "false"가 참일 때.

echo "\"false\" 테스트"
if [ "false" ]              #  "false"는 그냥 문자열 같죠?
then
  echo "\"false\" 는 참."   #+ 그래서 참이 되네요.
else
  echo "\"false\" 는 거짓."
fi

echo

echo "\"\$false\" 테스트"  # 초기화 안 된 변수, 다시.
if [ "$false" ]
then
  echo "\"\$false\" 는 참."
else
  echo "\"\$false\" 는 거짓."
fi                          # 흠, 이게 우리가 원하던 거죠.


echo

exit 0

연습문제. 위에 나온 예 7-1의 동작을 설명해 보세요.

if [ condition-true ]
then
   command 1
   command 2
   ...
else
   # 옵션(필요 없다면 빠져도 됩니다).
   # 원래 조건이 실패했을 경우 동작할 코드들을 두세요.
   command 3
   command 4
   ...
fi

'if'와 'then'을 같은 줄에 두려면 세미콜론을 쓰세요.

if [ -x "$filename" ]; then

Else if 와 elif

elif

elifelse if의 단축형입니다. 바깥쪽 if/then의 안쪽에 중첩해서 쓰는 효과를 가져옵니다.

if [ condition1 ]
then
   command1
   command2
   command3
elif [ condition2 ]
# else if 와 같습니다.
then
   command4
   command5
else
   default-command
fi

if test condition-trueif [ condition-true ] 은 완전히 똑같은 표현입니다. [test 명령어를 부르는 토큰이기 때문에 ] 가 꼭 필요하진 않지만 새 버전의 bash 에서는 그래도 있어야 됩니다.

참고: test 명령어는 파일 타입을 테스트하거나 문자열을 비교해 주는 bash 내장 명령이기 때문에, Bash 스크립트안에서 testsh-utils 패키지의 일부분인 /usr/bin/test 외부 명령어를 부르지 않습니다. 비슷하게, [/usr/bin/test로 링크되어 있는 /usr/bin/[를 부르지 않습니다.

bash$ type test
test is a shell builtin
bash$ type '['
[ is a shell builtin
bash$ type '[['
[[ is a shell keyword
bash$ type ']]'
]] is a shell keyword
bash$ type ']'
bash: type: ]: not found
	      

예 7-2. [ ]test 의 동일함

#!/bin/bash

echo

if test -z "$1"
then
  echo "명령어줄 인자가 없습니다."
else
  echo "첫번째 명령어줄 인자는 $1 입니다."
fi


if [ -z "$1" ]    # 위의 코드 블럭과 기능적으로 동일합니다.
#   if [ -z "$1"   라고 해도 동작하겠지만...
#+  Bash 는 오른쪽 대괄호가 빠졌다고 에러 메세지를 냅니다.
then
  echo "명령어줄 인자가 없습니다."
else
  echo "첫번째 명령어줄 인자는 $1 입니다."
fi

echo

exit 0

[[ ]] 는 쉘 상에서 [ ]과 동일합니다. 이 명령어는 ksh88에서 따 온 확장 테스트 명령어입니다.

참고: [[]] 사이에서는 파일명 확장이나 낱말 조각남이 일어나지 않지만 매개변수 확장이나 명령어 치환은 일어납니다.

file=/etc/passwd

if [[ -e $file ]]
then
  echo "비밀번호 파일이 존재합니다."
fi

작은 정보: [ ... ] 말고 [[ ... ]] 를 쓰면 많은 논리적 에러들을 막을 수 있습니다. 예를 들어 &&, ||, <, > 연산자들은 [ ] 에서 에러를 내지만 [[ ]] 에서는 잘 동작합니다.

참고: if다음에 꼭 test나 테스트 대괄호( [ ]나 [[ ]] )가 나오지 않아도 됩니다.
dir=/home/bozo
if cd "$dir" 2>/dev/null; then   # "2>/dev/null" 는 에러 메세지를 숨겨줍니다.
  echo "현재 디렉토리는 $dir 입니다."
else
  echo "$dir 로 옮겨갈 수 없습니다."
fi
"if COMMAND" 문은 COMMAND의 종료 상태를 리턴합니다.

비슷하게, 테스트 대괄호가 리스트와 같이 쓰이면 if 없이 단독으로 쓰일 수도 있습니다.
var1=20
var2=22
[ "$var1" -ne "$var2" ] && echo "$var1 는 $var2 와 같지 않습니다."

home=/home/bozo
[ -d "$home" ] || echo "$home 디렉토리는 존재하지 않는 디렉토리입니다."

(( )) 문은 산술식을 평가해서 확장해 줍니다. 그 산술식이 0 으로 평가되면 종료 상태 1이나 "false"를 리턴하고 0 이 아닌 값으로 평가되면 종료 상태 0이나 "true"를 리턴합니다. 앞에서 얘기했던 test[ ]와 현격한 차이를 보여줍니다.

예 7-3. (( ))로 산술식 테스트 하기

#!/bin/bash
# 산술 테스트.

# (( ... )) 는 산술문을 평가하고 테스트 해 줍니다.
# 종료 상태는 [ ... ] 와 반대입니다!

(( 0 ))
echo "\"(( 0 ))\" 의 종료 상태는 $?."   # 1

(( 1 ))
echo "\"(( 1 ))\" 의 종료 상태는 $?."   # 0

(( 5 > 4 ))                             # 참
echo $?                                 # 0

(( 5 > 9 ))                             # 거짓
echo $?                                 # 1

exit 0