如果源函数脚本在函数中运行,为什么bash变量不是全局变量?

时间:2018-04-11 10:26:42

标签: bash scope

通常从另一个脚本获取文件,我可以访问它的变量。

如果我从函数中获取脚本,其变量不是全局,这似乎与联机帮助页相矛盾:

  

功能可以使用local builtin命令声明函数本地的变量。通常,变量及其值在函数及其调用者之间共享。

     

source filename [arguments] 在当前shell环境中从filename读取和执行命令

发生我所有方便的版本:3.2.57(1)-release(x86_64-apple-darwin17),4.3.42(1)-release(x86_64-suse-linux-gnu)和版本4.3.48 (1)-release(x86_64-pc-linux-gnu)

test-sourced.sh:

#!/bin/bash
echo $BASH_SOURCE $$ $SHLVL
declare -x FOO=bar
foo() { echo funfoo=$FOO $$ $SHLVL ; }

test-top.sh:

#!/bin/bash
echo $BASH_SOURCE $$ $SHLVL

funcsource () { source ./test-sourced.sh ; }
echo ==== funcsource...
funcsource
echo foo=$FOO
foo

echo ==== source...
source ./test-sourced.sh
echo foo=$FOO
foo

我看到了这个输出,但是期望看到funcsource和source做同样的事情:

$ ./test-top.sh 
./test-top.sh 1234 2
==== funcsource...
./test-sourced.sh 1234 2
foo=
funfoo= 1234 2
==== source...
./test-sourced.sh 1234 2
foo=bar 1234 2
funfoo=bar

它是相同的PID和相同的shell级别,所以它看起来像故意行为。这是一个错误,还是我错过了什么?

更新:回复$ FOO并在source命令之后立即在函数中运行'foo'给出它们的值,所以它们已经到了那么远但由于某种原因保持在函数范围内。这仍然与手册相矛盾。

2 个答案:

答案 0 :(得分:3)

出现这种行为的原因是因为你正在使用内置的declare shell。根据{{​​1}}:

  

在函数中使用时,help declare会使NAME成为本地名称,与declare一样   命令。 local选项会抑制此行为。

-g更改为使用test-sourced.sh而不是declare -g(将变量导出到环境中) - 或常规的shell变量赋值 - 应该显示预期的行为(变量是全局的) ):

declare -x

如果希望从该shell会话启动的未来子进程可以访问该变量,那么将该变量导出到环境只会添加实用程序。如果这是您想要的,您可以使用以下任一Bash结构来确保变量是全局变量和导出变量:

#!/bin/bash
echo $BASH_SOURCE $$ $SHLVL

# Simple shell variable assignment (global by default)
FOO=bar

# Use declare to globally assign a value to the shell variable
declare -g FOO=bar

foo() { echo funfoo=$FOO $$ $SHLVL ; }

答案 1 :(得分:0)

使用export代替declare -x,声明将变量范围限制为无法在外部显示。

#!/bin/bash
echo $BASH_SOURCE $$ $SHLVL
export FOO=bar  #or FOO=bar 
foo() { echo funfoo=$FOO $$ $SHLVL ; }