Reputation: 3401
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.
Upvotes: 6
Views: 4124
Reputation: 12013
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 thelocal
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
Upvotes: 6
Reputation: 1315
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 ; }
Upvotes: 0