-1

I want to write a function similar to the read built-in, where I pass a variable name as an argument, and the function returns its result into the variable named.

I tried doing it like this:

GLOBAL_VAR=0

foo() {
    local var="$1"; shift
    local result

    # ...

    (( GLOBAL_VAR++ ))

    # ...

    eval "${var}=\${result}"
}

There is a problem with the above, though: the above doesn’t work if I call foo with the first argument var or result, because then the assignment becomes to the local variable defined inside foo instead of its caller. In effect, this leaks the implementation of foo.

If I use a nameref instead (local -n), running foo var results in a warning message, while foo result returns nothing to the caller, because the result variable is assigned within the function. And I cannot just rename the variable to something that will not conflict, because I actually intend to perform recursion here, so the variable will inevitably clash with itself. Namerefs don’t help with my problem at all.

I cannot use a subshell either, because then any modifications to global variables will be lost.

Is there a way to assign to a dynamically-named variable as defined in the context of the caller?

(In other words, I am looking for the bash equivalent of Tcl’s upvar and/or uplevel.)

user3840170
  • 22,750
  • 2
  • 21
  • 50
  • Does this answer your question? [Passing arguments by reference](https://stackoverflow.com/questions/540298/passing-arguments-by-reference) – KamilCuk May 05 '20 at 18:05
  • In functions, `declare` makes variables local, so I cannot use that. And the linked answer does not help for the problem in this question: using it results in `environment: warning: var: circular name reference`. – user3840170 May 05 '20 at 18:11
  • 1
    `declare makes variables local` when used without specific arguments, yes. Why does it matter? `environment: warning: var: circular name reference` and there is no possible solution to that problem. So `declare -n _pIcK_uNiQuE_NaMe_FoR_nAmE_rEfErEnCe="$1"` – KamilCuk May 05 '20 at 18:13
  • @user3840170: You haven't answered to the above comment. Why does the reference variable's name in the function matter at all? – Inian May 05 '20 at 18:22
  • The question has been the same from the beginning: how to modify a variable in the caller of a function without leaking the function’s implementation details. Never mind `declare`, that isn’t actually a problem; the problem is that namerefs point to variables in the function’s context, not its caller like I wanted. – user3840170 May 05 '20 at 18:48
  • @user3840170: I'm not sure there is a straightforward way to do that in `bash`. Good luck downvoting the answers and trying to find an answer – Inian May 05 '20 at 19:00
  • 1
    Related: [Circular name references in bash shell function, but not in ksh](https://unix.stackexchange.com/questions/302578/circular-name-references-in-bash-shell-function-but-not-in-ksh). I thought Bash 5 was supposed to fix that, but like Kusalananda's answer there shows, it really doesn't do it well. – ilkkachu Mar 02 '21 at 09:58

1 Answers1

-1

I suspect you'll end up with something like:

foo() {
    local result
    result="some computation with $1"
    echo "$result"
}

thing=$(set -eu; foo)
dstromberg
  • 6,698
  • 24
  • 25