为什么这个自定义源代码函数不会使我声明的变量全局可用?

时间:2016-11-11 14:20:14

标签: bash scope global-variables

我面临一个非常奇怪的问题。我知道我错过了一些基本的东西,但对于我的生活,我无法弄清楚是什么。

在文件tmp.sh中考虑这些声明:

declare -A aa
aa[1]=hello
aa[2]=world

myfunc() {
    echo exists
}

myvar=exists

我将脚本作为source tmp.sh来源并运行:

myfunc
echo $myvar
echo ${aa[@]}

输出结果为:

exists
exists
hello world

现在我做同样的事情,但把源语句放在一个函数中:

mysource() {
    filename="$1"
    source "$filename" 
}

这次输出是:

exists
exists

这里发生了什么?

2 个答案:

答案 0 :(得分:2)

-g选项添加到declare [1]

来自手册

  

-g在shell函数中使用时创建全局变量;否则忽略(默认情况下,声明在shell函数中使用时声明局部作用域变量)

从chepner的评论中提及

也很有用
  

source的工作原理是执行文件的内容,就像将source命令替换为文件内容一样。即使声明语句不在文件中的函数中,它们也是调用source的函数的一部分。

[1] -g选项需要Bash 4.2 or above

答案 1 :(得分:0)

补充123's helpful answer

  • 默认情况下,declare函数中使用时会创建本地变量(换句话说:在函数内部{{1}默认情况下,行为与declare)相同。

  • 从函数内部创建全局变量:

    • Bash local

      • 使用4.2+(例如declare -g
    • 较早的Bash版本,包括declare -g foo='bar'

      • 只需为变量指定值(例如3.x),不要使用foo='bar'

暂且不说:

您的示例代码使用declare来声明关联数组,这需要Bash declare -A

关联数组是唯一类型的(非环境)变量,它们严格需要 4.0语句来创建它们 - 你不能创建没有declare的关联数组,而你可以通过简单的赋值隐式地创建(非整数类型的)标量和数组。

因此,鉴于declare -A需要Bash declare -g,如果您碰巧遇到4.24.0,则无法解决您的问题。

4.1版本的Bash不会遇到此问题,因为他们并不完全支持3.x