title: Scoping issue memoising bash function with associative array
body: <p>I have a bash script which uses <code>jq</code> to look up 'dependency' data in some JSON, and take the closure (find dependencies of dependencies of dependencies, etc.).</p>
  
  <p>This works fine, but can be very slow, since it may look up the same dependencies over and over, so I'd like to memoise it.</p>
  
  <p>I tried using a global associative array to associate arguments with results, but the array doesn't seem to be storing anything.</p>
  
  <p>I've extracted the relevant code into the following demo:</p>
  
  <pre><code>#!/usr/bin/env bash
  
  # Associative arrays must be declared; use 'g' for global
  declare -Ag MYCACHE
  function expensive {
      # Look up $1 in MYCACHE
      if [ "${MYCACHE[$1]+_}" ]
      then
          echo "Using cached version" &gt;&gt; /dev/stderr
          echo "${MYCACHE[$1]}"
          return
      fi
  
      # Not found, perform expensive calculation
      RESULT="foo"
  
      echo "Caching result" &gt;&gt; /dev/stderr
      MYCACHE["$1"]="$RESULT"
  
      # Check if the result was cached
      if [ "${MYCACHE[$1]+_}" ]
      then
          echo "Cached" &gt;&gt; /dev/stderr
      else
          abort "Didn't cache"
      fi
  
      # Done
      echo "$RESULT"
  }
  
  function abort {
      echo "$1" &gt;&gt; /dev/stderr
      exit 1
  }
  
  # Run once, make sure result is "foo"
  [[ "x$(expensive "hello")" = "xfoo" ]] ||
      abort "Failed for hello"
  
  # Run again, make sure "Using cached version" is in stderr
  expensive "hello" 2&gt;&amp;1 &gt; /dev/null | grep "Using cached version" ||
      abort "Didn't use cache"
  </code></pre>
  
  <p>Here are my results:</p>
  
  <pre><code>$ ./foo.sh 
  Caching result
  Cached
  Didn't use cache
  </code></pre>
  
  <p>The fact we get <code>Cached</code> seems to indicate that I'm storing and looking up values correctly, but they're not preserved across invocations of <code>expensive</code> since we hit the <code>Didn't use cache</code> branch.</p>
  
  <p>It looks like a scoping issue to me, maybe caused by the <code>declare</code>. However, <code>declare -A</code> seems to be a requirement for using associative arrays.</p>
  
  <p>Here's my bash version:</p>
  
  <pre><code>$ bash --version
  GNU bash, version 4.3.42(1)-release (i686-pc-linux-gnu)
  Copyright (C) 2013 Free Software Foundation, Inc.
  License GPLv3+: GNU GPL version 3 or later &lt;http://gnu.org/licenses/gpl.html&gt;
  
  This is free software; you are free to change and redistribute it.
  There is NO WARRANTY, to the extent permitted by law.
  </code></pre>
  
  <p>As well as figuring out the behaviour I'm experiencing, I'd also appreciate alternative ways of memoising functions in bash (preferably nothing which touches the filesystem, even if it's RAM-based)</p>