bash question: command substitution is eating my arrays!

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

bash question: command substitution is eating my arrays!

Karl Auer
The script below displays some (for me) surprising behaviour.

I want a function to update an array and return some output[1].

The first loop, which captures the function's output, does not work -
inside the function it clearly does update the array, but outside the
function the array stays empty. Note that it contains no values after
the first loop completes.

The second loop works as expected in that the array collects all the
test values, and still has them after the second loop completes - but
the calls don't capture the function's output.

The ONLY difference between the loops is that the first captures the
function's output.

What am I missing? Why does capturing the output from the function seem
to clear the array?

Here is the script:

    #!/bin/bash

    declare -A TEST

    add_element() {
       KEY="$1"
       local VALUE="$KEY-floop"

       TEST["$KEY"]="$VALUE"
       echo "$VALUE"
       echo "This: TEST[$KEY] = ${TEST["$KEY"]} Count: ${#TEST[@]}" >&2
    }

    for i in one two three four ; do
    {
       X=$(add_element $i)
    }
    done
    echo "After first loop, count is ${#TEST[@]}"
    echo "Values: ${!TEST[@]}"
    echo

    for i in one two three four ; do
    {
       add_element $i
    }
    done
    echo "After second loop, count is ${#TEST[@]}"
    echo "Values: ${!TEST[@]}"

This is the output from the above:

    This: TEST[one] = one-floop Count: 1
    This: TEST[two] = two-floop Count: 1
    This: TEST[three] = three-floop Count: 1
    This: TEST[four] = four-floop Count: 1
    After first loop, count is 0
    Values: 

    one-floop
    This: TEST[one] = one-floop Count: 1
    two-floop
    This: TEST[two] = two-floop Count: 2
    three-floop
    This: TEST[three] = three-floop Count: 3
    four-floop
    This: TEST[four] = four-floop Count: 4
    After second loop, count is 4
    Values: four one two three

Regards, K.

[1] I want to cache some values, so the function I really want will be
passed a key. If the key exists in the global array the function should
output the value. If the key is not in the array, the function should
go find the appropriate value for the key, put it in the array, and
then output the value. Getting the value for a given key is very
costly, hence the desire to cache them. While I could build the entire
cache first, that would be a major change to my script's logic and a
last resort, not least because it would have to cache all the possible
keys, though any given run will only need a few of them. 

--
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Karl Auer ([hidden email])
http://www.biplane.com.au/kauer
http://twitter.com/kauer389

GPG fingerprint: 8D08 9CAA 649A AFEF E862 062A 2E97 42D4 A2A0 616D
Old fingerprint: A0CD 28F0 10BE FC21 C57C 67C1 19A6 83A4 9B0B 1D75



--
ubuntu-users mailing list
[hidden email]
Modify settings or unsubscribe at: https://lists.ubuntu.com/mailman/listinfo/ubuntu-users
Reply | Threaded
Open this post in threaded view
|

Re: bash question: command substitution is eating my arrays!

Karl Auer
On Mon, 2019-10-28 at 03:57 +1100, Karl Auer wrote:
> The script below displays some (for me) surprising behaviour.

I've done a bit more research on this and come to the conclusion that
while it is not actually impossible, the available solutions in bash
are complicated and mostly unreadable.

Please don't waste your time on this issue, I apologise for bringing it
up.

My solution was to move the caching logic into my main loop, and only
do the expensive query in a separate function. It's not as nice as
hiding the cache and the query in one function, but it is not too bad,
quite readable, and it works well. My script run time has dropped by
80%, so I'm happy :-)

Regards, K.

--
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Karl Auer ([hidden email])
http://www.biplane.com.au/kauer
http://twitter.com/kauer389

GPG fingerprint: 8D08 9CAA 649A AFEF E862 062A 2E97 42D4 A2A0 616D
Old fingerprint: A0CD 28F0 10BE FC21 C57C 67C1 19A6 83A4 9B0B 1D75



--
ubuntu-users mailing list
[hidden email]
Modify settings or unsubscribe at: https://lists.ubuntu.com/mailman/listinfo/ubuntu-users