6

I need to remove all of the keys and values from an associative array in Bash. GNU bash, version 4.4.20(1)-release (x86_64-pc-linux-gnu). I cannot just unset it, because I need to do this inside a function. If I unset it, and then declare it again, it will only be local to the function.

arrayFunction()
{
    # Start the array Clearer
    unset workingArray
    declare -A workingArray
    # End the array Clearer

    workingArray[test]="bar"
    echo "Inside the function: ${workingArray[test]}"
}

declare -A workingArray

workingArray[test]="foo"

echo "Before the function: ${workingArray[test]}"

arrayFunction

echo "After the function: ${workingArray[test]}"

Output:

Before the function: foo
Inside the function: bar
After the function:

That last line of the output should be bar.

What I am looking for is some code to put inside the function that will empty the array ENTIRELY, while keeping the array global.

3 Answers 3

8

Well it's not really complex, just use -g.

Inside your function:

declare -gA workingArray

and this will happen gloabally.

Sign up to request clarification or add additional context in comments.

2 Comments

Wow. Obviously there would be something so stupidly simple, that I could have found in like 5 seconds with declare --help. Thank you!
More specifically, "When used in a function, declare makes each name local, as with the local command, unless the -g option is used" gnu.org/software/bash/manual/bash.html
4

TLDR: use unset

unset arr
declare -A arr # -g doesn't matter to the root of the question

Explanation

I found that declare -gA arr was insufficient if that array needed to be reset in the same scope. For example,

for file in `ls`; do
  declare -gA one_file
  safe_file=$(echo $file | tr '.' '_')  # simplified; mileage may vary
  one_file[${safe_file}]=foo
  printf "%s\n" "${!one_file[@]}"
done

outputs:

# what you'd expect if the array is never cleared out
(a lot of files -- file 1, file 2, ..., file i for i in range (1, N)) 

Solution

What works is unset:

for file in `ls`; do
  unset one_file

  # You may have to add -g for 'global' 
  # if you are declaring w/in a function,
  # and using outside of it: declare -Ag <your_arr>

  declare -A one_file

  safe_file=$(echo $file | tr '.' '_')
  one_file["${safe_file}"]=foo
  printf "%s\n" "${!one_file[@]}"
done

Outputs each file 1 and only 1 time -- the array was cleared out each time.

3 Comments

Thanks a lot. Pretty frustrating that anything declared within a for loop would have a scope beyond that for.
The unset and the -g of declare serve different purposes. You do need the unset, but the OP was using declare in a function, which (without the -g) makes it local to the function. So, they need both.
yeah, on a second read looks like you need the -g inside the function to do what the OP wants in addition to an unset. But to clear the array: unset. To declare an array w/ global scope: -g.
2

The question ask to "remove all of the keys and values". However, from the sample code, it looks as if the request is to REPLACE all existing keys and values with new set of keys/values. This can be achieved with assignment to the associative array.

arrayFunction()
{
    workingArray=( [test]="bar" )
    echo "Inside the function: ${workingArray[test]}"
}

If the new key/values set is dynamic, it can be build incrementally

arrayFunction()
{
    # Start with empty set
    workingArray=()
    workingArray[test]=bar
    workingArray[lazy]=dog
    # Additional assignments
    echo "Inside the function: ${workingArray[test]}"
}

In both cases, there is no need to re-declare the array.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.