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.
Global variables They are visible and valid anywhere in the bash script. You can even get its value from inside the function. If you declare a global variable within a function, you can get its value from outside the function.
The source Command The built-in bash source command reads and executes the content of a file. If the sourced file is a bash script, the overall effect comes down to running it. We may use this command either in a terminal or inside a bash script.
The easiest way to set environment variables in Bash is to use the “export” keyword followed by the variable name, an equal sign and the value to be assigned to the environment variable.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With