6

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 [...]

-n Give each name the nameref attribute, making it a name reference to another variable. That other variable is defined by the value of name. All references and assignments to name, except for changing the -n attribute itself, are performed on the variable referenced by name's value.

[...]

When used in a function, declare and typeset make each name local, as with the local command, unless the -g option is supplied. If a variable name is followed by =value, the value of the variable is set to value.

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 "%s\n" "$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".

  • Same behavior in 4.4.0(5)-rc2; I'd report this as a bug. – chepner Aug 11 '16 at 0:31
  • Actually, it's a known problem: mywiki.wooledge.org/BashFAQ/… – chepner Aug 11 '16 at 0:35
  • 1
    As a practical solution, consider deploying ksh93 everywhere. It's been open source for years. – Gilles Aug 11 '16 at 0:56
  • @chepner I reported it to bug-bash last night. Thanks for the wiki reference, I hadn't seen it. The suggestion therein is the same as my workaround (use unique variable names). – Kusalananda Aug 11 '16 at 4:22
  • @Gilles I wish I could! :-) This came up when rewriting a small library of ksh93 shell utils so that they would be usable in bash too... – Kusalananda Aug 11 '16 at 4:59
3

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.