I get a suprising behaviour when I have a function local read-only variable and global read-only variable with the same name.
When read-only option is removed from global declaration. I.e.
declare -r var="main"
is changed to:
declare var="main"
I get the expected behaviour. I've been reading bash man page but I can't find an explanation to this behaviour. Could you please point me to the section(s) of the manual explaining the issue ?
I think this is a similar kind of issue than How does lexical scoping supported in different shell languages? but more specific.
Details:
$ cat readonly_variable.sh
#!/bin/bash
# expected output:
#
# BASH_VERSION = 3.2.25(1)-release
# function
# main
#
# but instead getting:
#
# BASH_VERSION = 3.2.25(1)-release
# ./readonly_variable.sh: line 6: local: var: readonly variable
# main
# main
#
# when read-only option (-r) is removed from global declaration (*), the output
# is expected
set -o nounset
function func {
local -r var="function"
echo "$var"
}
declare -r var="main" # (*)
echo BASH_VERSION = $BASH_VERSION
echo $(func)
echo $var
exit 0
I'm stucked to this particular Bash version.
$ ./readonly_variable.sh
BASH_VERSION = 3.2.25(1)-release
./readonly_variable.sh: line 24: local: var: readonly variable
main
main
$
It is usually not a good programming practice to give different variables the same names. If a global and a local variable with the same name are in scope, which means accessible, at the same time, your code can access only the local variable.
Although it is usually a bad idea, you can declare a formal parameter or a local variable with the same name as one of the instance variables.
2 Answers. Show activity on this post. In C, multiple global variables are "merged" into one. So you have indeed just one global variable, declared multiple times.
The shell provides a way to protect variables as read-only by using the readonly command. After a variable is marked read-only, we cannot change the value of the variable. As we can see from the output, we cannot assign to the variable declared as readonly.
Actually, making local copies of readonly global variables is explicitely forbidden for security reasons, as documented in bash source code (in variables.c:make_local_variable
):
The test against old_var's context level is to disallow local copies of readonly global variables (since "I" believe that this could be a security hole).
(where "I" is not me, I'm merely quoting)
/* Since this is called only from the local/declare/typeset code, we can
call builtin_error here without worry (of course, it will also work
for anything that sets this_command_name). Variables with the `noassign'
attribute may not be made local. The test against old_var's context
level is to disallow local copies of readonly global variables (since I
believe that this could be a security hole). Readonly copies of calling
function local variables are OK. */
if (old_var && (noassign_p (old_var) ||
(readonly_p (old_var) && old_var->context == 0)))
{
if (readonly_p (old_var))
sh_readonly (name);
return ((SHELL_VAR *)NULL);
}
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