쉘이 재귀를 지원합니까?

쉘이 재귀를 지원합니까?

쉘 스크립트에서 재귀 함수를 작성하려고 합니다. 다음 코드를 고려해보세요.

function printA {
    if [[ "$1" = 0 ]]; then
        return
    else
        echo "a$(printA $(("$1" - 1)))"
    fi
}

printA 10

function factorial {

    if [[ "$1" = 0 ]]; then
        return 1
    else
        return $(( "$1" * $(factorial $(( $1 - 1 )) ) ))
    fi
}

echo $(factorial 5)    

코드가 실패합니다.

  • bash(3.0)

recur.sh: 5행: "10" - 1: 구문 오류: 피연산자 필요(오류는 ""10" - 1"로 표시됨)

recur.sh: 16행: "1" * : 구문 오류: 피연산자가 필요합니다(오류는 ""1" * "로 표시됨).

recur.sh: 16행: "2" * : 구문 오류: 피연산자가 필요합니다(오류는 ""2" * "로 표시됨).

recur.sh: 라인 16: "3"*: 구문 오류: 피연산자 필요(오류는 ""3"*"로 표시됨)

recur.sh: 16행: "4" * : 구문 오류: 피연산자가 필요합니다(오류는 ""4" * "로 표시됨).

recur.sh: 16행: "5" * : 구문 오류: 피연산자가 필요합니다(오류는 ""5" * "로 표시됨).

  • zsh(4.2.1)

printA:1: 잘못된 수학 표현: 잘못된 문자: "

팩토리얼: 5: 잘못된 수학 표현: 잘못된 문자: "

그러나 부분적으로 성공적으로 사용되었습니다 ksh88. 두 번째 기능만 실패했습니다.

아 아 아 아 아

recur.sh[5]: 1 * : 더 많은 토큰이 예상됩니다.

recur.sh[5]: 2 * : 더 많은 토큰이 예상됩니다.

recur.sh[5]: 3 * : 더 많은 토큰이 예상됩니다.

recur.sh[5]: 4 * : 더 많은 토큰이 예상됩니다.

recur.sh[5]: 5 * : 더 많은 토큰이 예상됩니다.

  • 내가 뭐 잘못 했어요?
  • bash와 zsh는 또 다른 재귀 구문을 지원합니까?
  • 왜 두 번째 함수( factorial)가 실패 합니까 ksh?

폴리스티렌:알고 있습니다. 재귀는 나쁘고 성능도 좋지 않습니다. 대신 일반 루프를 사용해야 합니다. bla bla bla. 재귀가 좋은지 나쁜지 논의하는 것이 아니라 일반 쉘이 이를 지원하는지 여부를 논의하는 것입니다. 나는 간단한 반복 루프가 트릭을 수행할 때 프로덕션에서 재귀 함수를 보낼 만큼 어리석지 않습니다. :)

답변1

  • 구문 오류: 산술 연산에는 따옴표가 사용되지 않습니다.
  • 논리 오류: STDOUT과 값을 혼합하고 있습니다 return.

값을 STDOUT으로 전달합니다.

function factorial {
    (( $1 )) &&
    echo $(( $1 * $( factorial $(( $1 - 1 )) ) )) ||
    echo 1
}

factorial 5

아니면 return그들은:

function factorial {
    (( $1 )) || return 1
    factorial $(( $1 - 1 ))
    return $(( $1 * $? ))
}

factorial 5
echo $?

두 코드 모두 bash, ksh(물론 93, 88에 대해서는 확실하지 않음) 및 에서 작동합니다 zsh. 따라서 쉘은 재귀를 지원합니다.

답변2

함수를 호출할 때 내부적으로 일어나는 일과 함정을 이해하는 한 재귀는 나쁘지 않습니다.

먼저, 재귀 함수가 작업을 완료할 때 실행될 중지 조건이 있는지 확인하세요. 이렇게 하지 않으면 재귀 함수가 아니라 루프 없는 함수를 갖게 됩니다.

다음은 변수와 재진입 지점입니다. 각 함수 호출은 재진입 지점의 주소(함수가 반환될 때 다음 명령어의 주소)에 정보를 푸시합니다. 그런 다음 tge 반환 값 유형을 위한 공간을 예약해야 합니다.

다음은 범위의 문제이다. 변수는 매개변수로 전달되고 지역변수는 함수에서 선언됩니다. 이 공간은 함수가 호출될 때마다 스택에 할당되어야 하며 호출 함수가 반환될 때 팝될 때까지 그대로 유지됩니다. 따라서 결국에는 스택 메모리가 부족해집니다(스택 오버플로 상황).

나는 DEC Vax에서 가르치는 파스칼 과정을 위한 "하노이 타워" 프로그램을 작성했습니다. 막대와 링을 원하는 만큼 추가하여 프로그램이나 VMS와 충돌하는 조건을 만들려고 합니다. 3개의 기둥에서 1000번의 회전을 완료했는데 프로그램이 계속 실행됩니다. 실행하는데 10분정도 걸렸는데 IR이 도망갔습니다.

어쨌든, 귀하의 질문으로 돌아갑니다. 여기서 일어나는 일은 변수가 잘못된 범위에 있는 것 같습니다. 로컬 환경이 아닌 전역 환경에서 호출되는 것처럼 보입니다. 따라서 함수에 의한 변수 변경 사항은 함수의 모든 인스턴스에 반영됩니다. 모든 변경은 로컬 범위에서 수행되어야 하며 그 값은 호출 함수에 반환됩니다. Bash와 같은 해석된 언어가 로컬 변수를 지원하고 각 변수를 모든 스크립트 논리에 표시할 수 있는지 확실하지 않습니다.

관련 정보