【问题标题】:Bash: Hide global variable using local variable with same nameBash:使用同名的局部变量隐藏全局变量
【发布时间】:2019-01-15 18:09:49
【问题描述】:

我想在函数中使用全局变量,但不希望更改超出函数范围。所以我定义了一个局部变量,初始化为全局变量的值。全局变量有一个很好的名字,所以我想在局部变量上使用相同的名字。这在 Bash 中似乎可行,但我不确定这是否是未定义的行为。

#!/bin/bash

a=3
echo $a
foo() {
    local a=$a  ##  defined or undefined?
    a=4
    echo $a
}
foo
echo $a

给出输出:

3
4
3

【问题讨论】:

  • 真的很奇怪的问题。为什么不尝试自己看看会发生什么:a=3;echo $a;foo(){ local a=$((a-2));回声 $a ; a=4;echo $a;};foo;echo $a

标签: bash scope


【解决方案1】:

扩展发生在分配之前(早期)为documentation states

拆分成单词后在命令行上进行扩展。

所以行为应该是可预测的(和定义的)。在 local a=$a 扩展 $a 时,它仍然是全局的。命令执行(赋值/声明)稍后发生(当$a 已经被它的值替换时)。

但是,我不确定如果本质上有两个不同的变量(取决于范围)具有相同的名称(即看起来是相同的),这不会让人感到困惑。所以,我宁愿质疑在编码实践/可读性/易于导航方面这样做是否明智。

【讨论】:

  • 即使先扩展,也不能保证local a=$a 语句按预期运行。如果a 是全局变量,某些语言甚至不允许这样的声明。需要引用 bash 范围规则,我在其手册页中几乎找不到。
  • 实际上是这样,因为赋值/声明(执行时)只是:local a=4(值从哪里来并不重要,此时信息已经消失) .其他语言真的没有什么意义。在 bash 中启动范围是相当基本的。
  • 我想参考 bash 中的作用域是相当基本的,以向自己保证 $alocal a=$a 确实指向全局变量,尽管我几乎相信这是真的。
  • This 可能是你能找到的最好的。
  • 动态范围很有趣:unset 可以在外部范围内取消设置变量并在外部范围内显示另一个变量。
【解决方案2】:

Bash 5.0 中有一个新的 shell 选项 localvar_inherit,可以让同名的局部变量继承前面作用域中同名变量的值:

#!/usr/bin/env bash

shopt -s localvar_inherit

myfunc() {
    local globalvar
    echo "In call: $globalvar"
    globalvar='local'
    echo "In call, after setting: $globalvar"
}

globalvar='global'
echo "Before call: $globalvar"
myfunc
echo "After call: $globalvar"

输出如下:

Before call: global
In call: global
In call, after setting: local
After call: global

如果您没有 Bash 5.0,则必须在函数中设置值,就像您在问题中所做的那样,结果相同。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-24
    • 2017-11-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多