쉘 함수에서 지역 변수의 범위


28

24.2를 읽은 후 . 지역 변수는 , 내가 변수 선언 생각 var키워드가 local의미하는 것을 var의 값이 함수의 중괄호로 구분 코드 블록 내에서만 액세스 할 수있었습니다.

그러나 다음 예제를 실행 한 후, 나는 그가 발견 var도 읽고, 액세스 코드의 블록에 의해 호출 기능에서 쓸 수 있습니다 - 즉,이 비록 var선언 localouterFunc, innerFunc여전히 그것을 읽고 그 값을 변경 할 수 있습니다.

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이 지적했듯이 이것은 실제로 예상되는 동작입니다.


그것은 예상되는 동작입니다
fpmurphy

2
출력의 마지막 줄에서 값 var이 비어있는 것이 이상하다고 생각하는 유일한 사람 입니까? var에 전역 적으로 설정되어 innerFunc있으므로 스크립트가 끝날 때까지 지속되지 않는 이유는 무엇입니까?
해롤드 피셔

답변:


22

쉘 변수에는 동적 범위가 있습니다. 변수가 함수의 로컬 변수로 선언되면 해당 범위는 함수가 반환 될 때까지 유지됩니다.

두 가지 예외가 있습니다.

  1. ksh93에서 함수가 표준 function_name () { … }구문으로 정의되면 로컬 변수는 동적 범위를 따릅니다. 그러나 함수가 ksh 구문으로 정의 된 경우 function function_name { … }로컬 변수는 어휘 / 정적 범위를 준수하므로이 함수는 다른 함수에서 볼 수 없습니다.

  2. zsh/private에 autoloadable 플러그인 zsh으로 제공하는 private키워드 / 내장 정적 범위의 변수를 선언하는 데 사용될 수있다.

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


쉘의 모든 변수에 동적 범위가 local있습니까? 또는로 선언 된 변수에만 적용 됩니까?
해롤드 피셔

@HaroldFischer 모든 변수에는 동적 범위가 있습니다. A를 typeset하거나 declare또는 local선언, 범위는 함수가 반환 될 때까지이다. 이러한 선언이 없으면 범위는 전체적입니다.
Gilles 'SO- 악마 그만'

6

버그가 아닙니다. outerFunc 컨텍스트 내부의 호출은 해당 로컬 $ var 복사본을 사용합니다. outerFunc의 "local"은 전역이 변경되지 않았 음을 의미합니다. outerFunc 외부에서 innerFunc를 호출하면 글로벌 $ var가 변경되지만 outerFunc의 로컬 $ var은 변경되지 않습니다. innerFunc에 "local"을 추가하면 outerFunc의 $ var는 변경되지 않습니다. 본질적으로 3 개가 있습니다.

  • $ global :: var
  • $ outFunc :: var
  • $ innerFunc :: var

Perl의 네임 스페이스 형식을 사용하려면


2

함수를 사용하여 로컬 범위를 강제 할 수 있습니다.

sh_local() {
  eval "$(set)" command eval '\"\$@\"'
}

예:

x() {
  z='new value'
  printf 'function x, z = [%s]\n' "$z"
}
y() {
  z='initial value'
  printf 'function y before x, z = [%s]\n' "$z"
  sh_local x
  printf 'function y after x, z = [%s]\n' "$z"
}
printf 'global before y, z = [%s]\n' "$z"
y
printf 'global after y, z = [%s]\n' "$z"

결과:

global before y, z = []
function y before x, z = [initial value]
function x, z = [new value]
function y after x, z = [initial value]
global after y, z = [initial value]

출처


2

에서 function innerFunc()var='new value'선언되지 않은 지역 , 그러므로 (함수가 호출 된 후) 눈에 보이는 범위에서 사용할 수 있습니다.

에 반대로, function outerFunc()local var='initial value'선언 된 지역 , 그러므로 (함수가 호출 된 경우에도) 전역에서 사용할 수 없습니다.

innerFunc()의 하위 항목으로 호출 되었으므로 outerFunc()var의 로컬 범위 내에 outerFunc()있습니다.

man 1 bash 명확히하는 데 도움이 될 수 있습니다

로컬 [옵션] [이름 [= 값] ...]

각 인수에 대해 name이라는 로컬 변수가 작성되고 값이 지정됩니다. 옵션은 선언에 의해 허용되는 옵션 중 하나 일 수 있습니다. 함수 내에서 local을 사용하면 변수 이름에 해당 함수와 해당 하위로 제한된 가시적 범위가 있습니다. ...

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

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


첫 번째 진술은 사용자가보고있는 것과 모순됩니다. 를 통해 var호출 한 후 전역 범위에서 값을 인쇄하면 인쇄 되지 않습니다 . innerFuncoutFuncnew value
Kusalananda
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.