Shell 函数中局部变量的作用域

mad*_*uri 47 shell bash shell-script function variable

阅读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}]"
Run Code Online (Sandbox Code Playgroud)

输出:

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:]
Run Code Online (Sandbox Code Playgroud)

问:这是我的 shell(bash 4.3.42、Ubuntu 16.04、64 位)中的错误还是预期的行为?

编辑:解决了。正如@MarkPlotnick 所指出的,这确实是预期的行为。

Gil*_*il' 39

Shell 变量具有动态范围。如果将变量声明为函数的局部变量,则该作用域将一直保留到函数返回,包括在调用其他函数期间。

有两个例外:

  1. 在 ksh93 中,如果一个函数是用标准function_name () { … }语法定义的,那么它的局部变量服从动态范围。但是如果一个函数是用 ksh 语法定义的,function function_name { … }那么它的局部变量服从词法/静态范围,所以它们在被 this 调用的其他函数中是不可见的。

  2. zsh/private在autoloadable插件zsh与提供了private关键字/内建可用于声明与静态范围的变量。

ash、bash、pdksh 和衍生物,bosh 只有动态范围。

  • @jinbeomhong 不,在词法范围内,当该函数调用另一个函数时,函数中的变量不可见。我已经添加了一个句子来明确说明这一点。 (2认同)

小智 8

这不是错误,outerFunc 上下文中的调用使用了 $var 的本地副本。externalFunc 中的“本地”意味着全局没有改变。如果在outerFunc 之外调用innerFunc,那么全局$var 会发生变化,但outerFunc 的本地$var 不会发生变化。如果你给innerFunc 添加了“local”,那么outerFunc 的$var 就不会改变——本质上,会有3 个:

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

使用 Perl 的命名空间格式,有点。


Jos*_*ris 6

function innerFunc()var='new value'虽不及申报地方,因此它可以在可见光范围内(一旦函数被调用)。

相反,function outerFunc()local var='initial value'被宣布为本地,因此它不是在全球范围内(即使函数被调用)提供。

因为innerFunc()作为 的孩子被调用outerFunc(),所以 var 在 的本地范围内outerFunc()

man 1 bash 可能有助于澄清

本地 [选项] [名称[=值] ...]

对于每个参数,都会创建一个名为 name 的局部变量,并为其赋值。该选项可以是declare 接受的任何选项。在函数中使用 local 时,它会导致变量名称的可见范围仅限于该函数及其子函数。...

这是一个在描述预期隐含的行为可以通过声明来实现local var='new valuefunction innerFunc()

正如其他人所说,这不是 bash shell 中的错误。一切都在正常运作。

  • 您的第一个陈述与用户所看到的内容相矛盾。通过“outFunc”调用“innerFunc”后,在全局范围内打印“var”的值,不会打印“new value”。 (2认同)