23.2. 지역 변수와 재귀 함수(Local Variables and Recursion)

재귀 함수는 지역 변수를 써서 구현할 수 있습니다.

지역 변수

지역적으로 선언된 변수는 선언된 곳이 포함되어 있는 코드 블럭에서만 보이게 됩니다. 즉, 지역적 "통용 범위"(local scope)를 갖습니다. 함수에 있어 지역 변수는 오직 그 함수 블럭 안에서만 의미를 갖습니다.

예 23-8. 지역 변수의 영역(Local variable visibility)

#!/bin/bash

func ()
{
  local a=23
  echo
  echo "함수 안에서 a = $a"
  echo
}  

func

# 이제 지역 변수인 'a'가 함수 밖에서도 보이는지 살펴보죠.

echo "함수 밖에서 a = $a"  # 아니죠. 'a'는 전역적으로 접근할 수 없습니다.
echo

exit 0

지역 변수를 쓰면 재귀 함수 [1] 를 쓸수 있지만, 이 방법은 일반적으로 쓸데 없이 많은 작업량을 필요로 하기 때문에 쉘 스크립트에서는 쓰지 않도록 권장합니다. [2]

예 23-9. 지역 변수를 쓴 재귀 함수

#!/bin/bash

#               factorial
#               ---------


# bash 가 재귀 함수를 지원할까요?
# 음, 그렇긴 하지만 재귀 함수를 쓰려면 머리가 뒤죽박죽 될 겁니다.


MAX_ARG=5
E_WRONG_ARGS=65
E_RANGE_ERR=66


if [ -z "$1" ]
then
  echo "사용법: `basename $0` number"
  exit $E_WRONG_ARGS
fi

if [ "$1" -gt $MAX_ARG ]
then
  echo "범위 초과(최대 5)."
  # 현실적으로 이것보다 더 큰 범위를 원한다면
  # 실제 프로그래밍 언어로 다시 작성하기 바랍니다.
  exit $E_RANGE_ERR
fi  

fact ()
{
  local number=$1
  # "number"를 지역 변수로 선언해 주지 않으면 제대로 동작하지 않습니다.
  if [ "$number" -eq 0 ]
  then
    factorial=1    # 0 의 팩토리얼 = 1.
  else
    let "decrnum = number - 1"
    fact $decrnum  # 재귀 함수 호출.
    let "factorial = $number * $?"
  fi

  return $factorial
}

fact $1
echo "$1 의 팩토리얼은 $? 입니다."

exit 0

스크립트에서 재귀 함수를 쓰는 예제인 예 A-11도 참고하세요. 스크립트에서 쓰이는 재귀 함수는 특히, 리소스를 많이 잡아 먹고 속도가 느리기 때문에 일반적으로 스크립트에는 적당하지 않습니다.

주석

[1]

Herbert Mayer재귀 함수"똑같은 알고리즘을 더 간단하게 써서 표현하는 것"이라고 정의했습니다. 재귀 함수란 자기 자신을 부르는 함수를 말합니다.

[2]

재귀가 너무 많이 일어나면 스크립트가 세그폴트(segfault)를 내면서 죽을 수도 있습니다.
#!/bin/bash

recursive_function ()		   
{
(( $1 < $2 )) && f $(( $1 + 1 )) $2;
#  첫번째 매개변수가 두번째보다 작은 동안
#+ 첫번째 매개변수를 하나 증가시키고 자신을 다시 부름.
}

recursive_function 1 50000  # 50,000 번의 재귀가 일어남!
# 당연히 세그폴트가 나겠죠.

# 재귀가 이렇게 많이 일어나면 스택에 할당된 메모리를 모두 써버리기 때문에
# C 프로그램이라도 세그폴트가 날 수 있습니다.

# Thanks, S.C.

exit 0  # 이 스크립트는 정상적으로 종료하지 못 합니다.