10.4. 테스트와 분기(Testing and Branching)

caseselect는 코드 블럭을 반복해서 수행하지 않기 때문에 기술적으로 루프가 아닙니다. 하지만 루프가 하는 것처럼 특정 블럭의 위나 아래에서 주어진 조건에 따라 프로그램 흐름을 조정해 줍니다.

코드 블럭에서 프로그램 흐름을 조절하기

case (in) / esac

case는 C/C++의 switch와 동일합니다. 조건에 따라 여러개의 코드 블럭중 하나로 분기할 수 있게 해주는데, 여러개의 if/then/else의 간단한 표기법처럼 동작하기 때문에 메뉴같은 것을 만들 때 적당합니다.

case "$variable" in

"$condition1" )
command...
;;

"$condition2" )
command...
;;

esac

참고:

  • 낱말 조각남(word splitting)이 일어나지 않기 때문에 꼭 variable을 쿼우팅 하지 않아도 됩니다.

  • 각 조건들은 오른쪽 괄호, )로 끝납니다.

  • 각 조건 블럭은 이중 세미콜론, ;;.

  • 전체 case 블럭은 esac로 끝납니다(case를 거꾸로 스펠링).

예 10-22. case 쓰기

#!/bin/bash

echo; echo "아무키나 누른 다음 리턴을 치세요."
read Keypress

case "$Keypress" in
  [a-z]   ) echo "소문자";;
  [A-Z]   ) echo "대문자";;
  [0-9]   ) echo "숫자";;
  *       ) echo "구두점이나, 공백문자 등등";;
esac  # [대괄호]속 범위의 문자들을 받아 들입니다.

# 독자들용 연습문제:
# 이 스크립트는 한개의 키누름만 받아들이고 종료합니다.
# 이를 키가 눌릴때마다 무슨 키인지 계속 보여주면서
# 키가 "X"일 경우에만 종료하도록 고쳐보세요.
# 힌트: "while"루프로 다 감싸면?

exit 0

예 10-23. case로 메뉴 만들기

#!/bin/bash

# 조잡한 주소 데이타베이스

clear # 화면을 정리하고

echo "          주소록"
echo "          ------"
echo "다음중 한 명을 고르세요:" 
echo
echo "[E]vans, Roland"
echo "[J]ones, Mildred"
echo "[S]mith, Julie"
echo "[Z]ane, Morris"
echo

read person

case "$person" in
# 변수가 쿼우트 된 것에 주의하세요.

  "E" | "e" )
  # 대소문자 모두 인식.
  echo
  echo "Roland Evans"
  echo "4321 Floppy Dr."
  echo "Hardscrabble, CO 80753"
  echo "(303) 734-9874"
  echo "(303) 734-9892 fax"
  echo "revans@zzy.net"
  echo "Business partner & old friend"
  ;;
# 이중 세미콜론이 각 옵션을 끝내게 해 주는 것을 눈여겨 봐두세요.

  "J" | "j" )
  echo
  echo "Mildred Jones"
  echo "249 E. 7th St., Apt. 19"
  echo "New York, NY 10009"
  echo "(212) 533-2814"
  echo "(212) 533-9972 fax"
  echo "milliej@loisaida.com"
  echo "Girlfriend"
  echo "Birthday: Feb. 11"
  ;;

# Smith & Zane 은 나중에 추가.

          * )
   # 디폴트 옵션.	  
   # 그냥 리턴을 쳐도 여기로 옵니다.
   echo
   echo "아직 등록이 안 돼 있습니다."
  ;;

esac

echo

# 독자용 연습문제:
# 입력을 한 번만 받고 끝내지 말고 계속 받을 수 있게 고쳐보세요.

exit 0

명령어줄 매개변수를 확인하려고 할 때, 아주 창의적인 방법으로 case를 사용하는 법을 보여 드리겠습니다.
#! /bin/bash

case "$1" in
"") echo "사용법: ${0##*/} <filename>"; exit 65;;  # 명령어 줄 매개변수를 안 적었거나 
                                                         # 첫번째 매개변수가 비어 있을 때
# ${0##*/} 는 매개변수 치환인 ${var##pattern} 이기 때문에 결과는 $0 이 됩니다.

-*) FILENAME=./$1;;   # 첫번째 인자($1)인 filename이 대쉬(-)로 시작한다면
                      # ./$1 로 바꿉니다.
                      # 따라서, 다른 명령어들은 이것을 옵션으로 해석하지 못하게 됩니다.

* ) FILENAME=$1;;     # 아무 것도 아니면, $1.
esac

예 10-24. case용 변수를 만들기 위해서 명령어 치환 쓰기

#!/bin/bash
# "case"용 변수를 만들기 위해서 명령어 치환 쓰기..

case $( arch ) in   # "arch" 는 머신 아키텍쳐를 리턴합니다.
i386 ) echo "80386 기반의 머신";;
i486 ) echo "80486 기반의 머신";;
i586 ) echo "Pentium 기반의 머신";;
i686 ) echo "Pentium2+ 기반의 머신";;
*    ) echo "다른 형태의 머신";;
esac

exit 0

caseglobbing용 패턴으로 문자열을 필터링 할 수 있습니다.

예 10-25. 간단한 문자열 매칭

#!/bin/bash
# match-string.sh: 간단한 문자열 매칭

match_string ()
{
  MATCH=0
  NOMATCH=90
  PARAMS=2     # 이 함수는 2개의 인자가 필요합니다.
  BAD_PARAMS=91

  [ $# -eq $PARAMS ] || return $BAD_PARAMS

  case "$1" in
  "$2") return $MATCH;;
  *   ) return $NOMATCH;;
  esac

}  


a=one
b=two
c=three
d=two


match_string $a     # 잘못된 인자 갯수
echo $?             # 91

match_string $a $b  # 일치하지 않음
echo $?             # 90

match_string $b $d  # 일치함
echo $?             # 0


exit 0		    

예 10-26. 입력이 알파벳인지 확인하기

#!/bin/bash
# 문자열을 필터링하기 위해서 "case" 구문 쓰기.

SUCCESS=0
FAILURE=-1

isalpha ()  # 입력 문자열의 "첫번째 문자"가 알파벳인지 아닌지 확인.
{
if [ -z "$1" ]                # 인자 없이 넘어왔군.
then
  return $FAILURE
fi

case "$1" in
[a-zA-Z]*) return $SUCCESS;;  # 문자로 시작하는지.
*        ) return $FAILURE;;
esac
}             # C 의 "isalpha()" 함수와 비교해 보세요.


isalpha2 ()   # "문자열 전체"가 알파벳인지 확인.
{
  [ $# -eq 1 ] || return $FAILURE

  case $1 in
  *[!a-zA-Z]*|"") return $FAILURE;;
               *) return $SUCCESS;;
  esac
}



check_var ()  # isalpha() 의 프론트엔드(front-end)
{
if isalpha "$@"
then
  echo "$* = 알파벳"
else
  echo "$* = 알파벳 아님"  # 인자가 없어도 "알파벳 아님"임.
fi
}

a=23skidoo
b=H3llo
c=-What?
d=`echo $b`   # 명령어 치환.

check_var $a
check_var $b
check_var $c
check_var $d
check_var     # 인자없이 부르면 어떻게 될까요?


# S.C. 가 더 좋게 고침.

exit 0
select

select는 Korn 쉘에서 따온 것인데 메뉴를 만들때 쓸 수 있습니다.

select variable [in list]
do
command...
break
done

사용자가 list에 있는 것중 하나를 고를 수 있게 해 줍니다. 기본적으로 PS3(#? ) 프롬프트를 쓰고 이 값은 바꿀 수 있다는 것에 주의하기 바랍니다.

예 10-27. select로 메뉴 만들기

#!/bin/bash

PS3='제일 좋아하는 야채를 고르세요: ' # 프롬프트 문자열 세트.

echo

select vegetable in "콩" "당근" "감자" "양파" "순무"
do
  echo
  echo "제일 좋아하는 야채가 $vegetable 이네요."
  echo "깔깔~~"
  echo
  break  # 여기에 'break'가 없으면 무한 루프를 돕니다.
done

exit 0

in list를 안 쓰면 select는 스크립트나 select를 포함하고 있는 함수로 넘어온 명령어 줄 인자($@)을 사용합니다.

in list가 빠졌을 경우를

for variable [in list]

의 경우와 비교해 보세요.

예 10-28. 함수에서 select를 써서 메뉴 만들기

#!/bin/bash

PS3='제일 좋아하는 야채를 고르세요: '

echo

choice_of()
{
select vegetable
# select 에 [in list] 가 빠져있기 때문에, 함수로 넘어온 인자를 씁니다.
do
  echo
  echo "제일 좋아하는 야채가 $vegetable 군요."
  echo "껄껄~~"
  echo
  break
done
}

choice_of 콩  쌀  당근  무  토마토  시금치
#         $1  $2  $3    $4  $5      $6
#         choice_of() 함수로 넘어갑니다.

exit 0