Shell 함수의 지역 변수 범위

Shell 함수의 지역 변수 범위

읽고 나서24.2. 지역변수var, 키워드를 사용하여 변수를 선언한다는 것은 함수의 중괄호로 구분된 코드 블록 내에서만 해당 값에 액세스할 수 있다는 local것을 의미한다고 생각했습니다 .var

var그러나 다음 예제를 실행한 후 이 코드 블록에서 호출된 함수에서 액세스하고 읽고 쓸 수도 있다는 것을 발견했습니다 . 즉 , 로 var선언된 경우에도 여전히 읽고 변경할 수 있습니다. 값.localouterFuncinnerFunc

Run It Online

#!/usr/bin/env bash

function innerFunc() {
    var='new value'
    echo "innerFunc:                   [var:${var}]"
}

function outerFunc() {
    local var='initial value'

    echo "outerFunc: before innerFunc: [var:${var}]"
    innerFunc
    echo "outerFunc: after  innerFunc: [var:${var}]"
}

echo "global:    before outerFunc: [var:${var}]"
outerFunc
echo "global:    after  outerFunc: [var:${var}]"

산출:

global:    before outerFunc: [var:]               # as expected, `var` is not accessible outside of `outerFunc`
outerFunc: before innerFunc: [var:initial value]
innerFunc:                   [var:new value]      # `innerFunc` has access to `var` ??
outerFunc: after  innerFunc: [var:new value]      # the modification of `var` by `innerFunc` is visible to `outerFunc` ??
global:    after  outerFunc: [var:]

Q: 이것은 내 셸(bash 4.3.42, Ubuntu 16.04, 64비트)의 버그입니까, 아니면 예상되는 동작입니까?

편집하다:해결되었습니다. @MarkPlotnick이 지적했듯이 이는 실제로 예상되는 동작입니다.

답변1

쉘 변수에는다이내믹 레인지. 변수가 함수에 대해 로컬로 선언되면 해당 범위는 함수가 반환될 때까지 유효하게 유지됩니다.다른 함수를 호출하는 동안 포함!

이는 대부분의 프로그래밍 언어와 뚜렷한 대조를 이룹니다.어휘 범위. Perl에는 다음 두 가지가 모두 있습니다.my어휘 범위의 경우,local또는 동적 범위가 없는 선언입니다.

두 가지 예외가 있습니다.

  1. ksh93에서 표준 구문을 사용하여 함수를 정의하면 function_name () { … }해당 지역 변수는 동적 범위 지정을 따릅니다. 그러나 함수가 ksh 구문을 사용하여 정의된 경우 function function_name { … }해당 지역 변수는 어휘/정적 범위를 따르므로 호출된 다른 함수에서는 표시되지 않습니다.

  2. zsh/private자동 로딩 플러그인은 정적 범위로 변수를 선언하는 데 사용할 수 있는 키워드/내장 함수를 제공 zsh합니다 private.

ash, bash, pdksh 및 그 파생물인 bosh에는 동적 범위만 있습니다.

답변2

function innerFunc()그 안에 var='new value'다음과 같이 선언했습니다.현지의이므로 가시 범위(함수 호출 후)에서 사용할 수 있습니다.

대신 선언 function outerFunc()에서 다음과 같이local var='initial value'현지의, 따라서 함수가 호출된 경우에도 전역적으로 사용할 수 없습니다.

var는 innerFunc()의 하위 항목으로 호출되므로 outerFunc()의 로컬 범위에 속합니다 outerFunc().

man 1 bash명확히 하는 데 도움이 될 수 있음

지역[옵션][이름[=값] ...]

각 매개변수에 대해 name이라는 지역 변수가 생성되고 값이 할당됩니다. 옵션은 허용 가능하다고 선언된 모든 옵션이 될 수 있습니다. 함수 내에서 로컬을 사용하면 변수 이름이 해당 함수와 해당 하위 함수에만 표시됩니다. ...

설명에서 예상되는 암시적 동작은 local var='new value에서 선언하여 달성할 수 있습니다 function innerFunc().

다른 사람들이 말했듯이 이것은 bash 쉘의 버그가 아닙니다. 모든 것이 예상대로 작동합니다.

답변3

이것은 버그가 아닙니다. externalFunc 컨텍스트의 호출은 $var의 로컬 복사본을 사용합니다. OuterFunc의 "local"은 전역이 변경되지 않음을 의미합니다. externalFunc 외부에서 innerFunc를 호출하면 전역 $var는 변경되지만 externalFunc의 로컬 $var는 변경되지 않습니다. innerFunc에 "local"을 추가하면 externalFunc의 $var는 변경되지 않습니다. 기본적으로 3개가 됩니다.

  • $global::var
  • $outerFunc::var
  • $innerFunc::var

일종의 Perl의 네임스페이스 형식을 사용합니다.

답변4

이는 예상된 동작입니다. 지역 변수에는 동적 범위가 있습니다. 변수는 선언된 함수가 반환될 때까지 범위 내에 유지됩니다. 따라서 이러한 변수는 이 함수에서 호출되는 모든 함수의 범위에 포함됩니다.

함수가 다른(로컬 또는 전역) 변수와 동일한 이름을 가진 새 로컬 변수를 선언하는 경우 새 로컬 변수는 별도의 메모리 영역에 상주하며 동일한 이름을 가진 다른 변수와 다른 값을 보유할 수 있습니다.

함수 내에서 로컬 선언이 나타나는 위치는 중요하지 않습니다.

예제로 제공된 코드를 약간 수정했습니다.

#!/usr/bin/env bash

function innerFunc() {
    echo "innerFunc:                   [var:${var}]"
}

function outerFunc() {
    local var='initial value'

    echo "outerFunc: before innerFunc: [var:${var}]"
    innerFunc
    echo "outerFunc: after  innerFunc: [var:${var}]"
}

echo "global:    before outerFunc: [var:${var}]"
outerFunc
echo "global:    after  outerFunc: [var:${var}]"
innerFunc
echo "global:    after  outerFunc: [var:${var}]"

관련 정보