I’m writing a set of shell functions that I want to have working in both Bash and KornShell93, but with Bash I’m running into a “circular name reference” warning.
This is the essence of the problem:
function set_it {
typeset -n var="$1"
var="hello:$var"
}
function call_it {
typeset -n var="$1"
set_it var
}
something="boff"
call_it something
echo "$something"
Running it:
$ ksh script.sh hello:boff $ bash script.sh script.sh: line 4: warning: var: circular name reference hello:
KornShell93 does exactly what I want, but Bash fails, and also warns about the same thing on line 2 if the something variable in the script is named var instead.
I’d like to have the var variable be local to each function, which is why I use typeset, but Bash doesn’t seem to like “dereferencing” a nameref to a variable with the same name as the nameref itself. I can’t use local -n or declare -n since it would break in ksh which lacks these, and even if I did, it doesn’t solve the issue.
The only solution I’ve found is to use unique variable names in each function, which seems rather silly since they are local.
The Bash manual says the following about typeset:
typeset[…]
-nGive each name thenamerefattribute, making it a name
reference to another variable. That other variable is
defined by the value ofname. All references and
assignments toname, except for changing the-n
attribute itself, are performed on the variable referenced by name’s value.
[…]
When used in a function,declareandtypesetmake each name
local, as with thelocalcommand, unless the-goption is
supplied. If a variable name is followed by=value, the
value of the variable is set tovalue.
It is obvious that there is something I don’t understand about Bash’s name references and function-local variables.
So, the question is: In this case, am I missing something about Bash’s handling of name reference variables, or is this a bug/mis-feature in Bash?
Update: I’m currently working with GNU bash, version 4.3.39(1)-release (x86_64-apple-darwin15) as well as with GNU bash, version 4.3.46(1)-release (x86_64-unknown-openbsd6.0). The Bash shipped with macOS is too old to know about name references at all.
Update: Even shorter:
function bug {
typeset -n var="$1"
printf "%sn" "$var"
}
var="hello"
bug var
Results in bash: warning: var: circular name reference. The var in the function should have different scope from the var in the global scope. This imposes an unnecessary restriction on the caller. The restriction being “you’re not allowed to name your variables whatever you want, because there may be a name clash with a (local) nameref in this function”.
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
Chet Ramey (Bash maintainer) says
There was extensive discussion about namerefs on bug-bash earlier this
year. I have a reasonable suggestion about how to change this behavior,
and I will be looking at it after bash-4.4 is released.
In the meanwhile, I’m resorting to slightly obfuscate the names of my local nameref variables, so that they don’t clash within the library nor (hopefully) with global shell variable names.
In bash 5.0, this is ever so slightly remedied (but not really fixed). The following is the observed behaviour:
$ foo () { typeset -n var="$1"; echo "$var"; }
$ var=hello
$ foo var
bash: typeset: warning: var: circular name reference
bash: warning: var: circular name reference
bash: warning: var: circular name reference
hello
This shows that it works, but that there also are are a few warnings.
The relevant NEWS entry says
i. A nameref name resolution loop in a function now resolves to a variable by that name in the global scope.
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0