Why are bash variables not global if sourced script runs in a function?

会有一股神秘感。 提交于 2021-01-22 18:03:59

问题


Sourcing a file normally from another script, I can access its variables.

If I source a script from within a function, its variables aren't global, which seems to contradict the manpage:

FUNCTION Variables local to the function may be declared with the local builtin command. Ordinarily, variables and their values are shared between the function and its caller.

source filename [arguments] Read and execute commands from filename in the current shell environment

Happens with all my conveniently available versions: 3.2.57(1)-release (x86_64-apple-darwin17), 4.3.42(1)-release (x86_64-suse-linux-gnu), and version 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

I see this output, but expected to see both funcsource and source do the same thing:

$ ./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

It's the same PID and the same shell level, so it looks like deliberate behaviour. Is this a bug, or am I missing something?


Update: echoing $FOO and running 'foo' in the function immediately after the source command DOES give their values, so they're getting that far but are for some reason kept local to the function scope. Which still seems to contradict the manual.


回答1:


The reason for this behaviour is because you’re using the declare shell builtin. According to help declare:

When used in a function, declare makes NAMEs local, as with the local command. The -g option suppresses this behavior.

Changing test-sourced.sh to use declare -g instead of declare -x (export the variable to the environment) – or a regular shell variable assignment – should show the expected behaviour (where the variable is global):

#!/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 ; }

Exporting the variable to the environment only adds utility if you want the variable to be accessible to future child processes started from that shell session. If this is what you want, you can use either of the following Bash constructs to ensure the variable is both global and exported:

export FOO=bar
declare -x -g FOO=bar



回答2:


Use export instead declare -x, declare limit the scope of variable to function doesn't visible outside.

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


来源:https://stackoverflow.com/questions/49772668/why-are-bash-variables-not-global-if-sourced-script-runs-in-a-function

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!