1

I'm working with this:

GNU bash, version 4.4.20(1)-release (x86_64-pc-linux-gnu)

I have a script like below:

#!/bin/bash

map2=()
result=""
f() {
    tmpA=(12 34 7844);
    map2=("${tmpA[@]}");
    echo true;
    return;
}

result=$(f)
echo result=$result : array=${map2[@]}

Which returns:

result=true : array=

if I replace result=$(f) simply by f it returns:

result= : array=12 34 7844

I could not find the way to modify the global array but also get the return value. Any idea on how to achieve this?

1

2 Answers 2

3

Any environment changes made inside $( ... ) are lost when it exits.

However, bash allows a way of changing arguments passed "by reference" by using the declare -n command:

#!/bin/bash

map2=()
result=""
f() {
    declare -n resultRef=$1
    declare -n map2Ref=$2

    local tmpA=(12 34 7844)
    map2Ref=("${tmpA[@]}")
    map2Ref[4]=999
    resultRef=true

    echo during: resultRef=$resultRef : arrayRef=${map2Ref[*]} : tmpA=${tmpA[*]}
}

f result map2

echo after: resultRef=$resultRef : arrayRef=${map2Ref[*]} : tmpA=${tmpA[*]}
echo result=$result : array=${map2[*]}

Variables declared in this way behave like local - they are discarded when the function returns.

during: resultRef=true : arrayRef=12 34 7844 999 : tmpA=12 34 7844
after: resultRef= : arrayRef= : tmpA=
result=true : array=12 34 7844 999
Sign up to request clarification or add additional context in comments.

2 Comments

+1. I was not aware this is possible: f() { declare -n b=$1; b=100; }; a=2; f a; echo "$a" (and you get 100).
@WalterA Unfortunately the implementation is not very robust. If one needs to pass complicated data structures around, switching to a "proper" language may be sensible.
3

Using command substitution (i.e., the $(f) construct), you are creating a subshell. Subshells inherit variables from their parent shells, but a subshell cannot modify its parent shell environment.

If you just call your function and check its exit code $? then you should be able to generate your desired output:

#!/bin/bash

map2=()
result="false"
my_func() {
    tmpA=(12 34 7844)
    map2=("${tmpA[@]}")
}

if my_func ; then
    result="true"
fi

printf "result=%s : array=%s\n" "$result" "${map2[@]}"

Output:

result=true : array=12 34 7844

Note that you can use bash -x yourscript to enable xtrace for more debugging output and you can paste your script into https://www.shellcheck.net/ for help as well.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.