Associative arrays: error "declare: -A: invalid option"

BashAssociative Array

Bash Problem Overview


I've written a script that uses associative arrays in bash (v 4).

It works fine on my local machine which is using 4.1.5(1)-release.

On the production machine, using 4.1.0(1)-release the following line, which declares the assoc array, fails:

declare -A uniqjars

with the message:

/script.sh: line 11: declare: -A: invalid option
declare: usage: declare [-afFirtx] [-p] [name[=value] ...]

I was under the impression this was a general bash 4 feature?

In the man for bash on the production machine it discusses using -A so I assume it should work.

> Associative arrays are created using > declare -A name.

I can confirm the script is using the right version of bash by printing out the value of echo 'bash -version.

What could I be doing wrong?

Bash Solutions


Solution 1 - Bash

Make sure the version of bash being invoked as interpreter at the top of your shell script (#!/bin/bash or whatever) is also version 4. If you're doing:

bash --version

and it's giving you v4, do a which bash to check it's location.

Solution 2 - Bash

The following seems to be a typical scenario on macOS after installing a newer Bash with Homebrew:

  • /bin/bash is the old Bash, 3.2
  • /usr/local/bin/bash is the new Bash that knows about associative arrays (4.0 or newer)
  • type bash points to /usr/local/bin/bash and bash --version is the new one (because it resolves to /usr/local/bin/bash --version)

However, scripts with a #!/bin/bash shebang line that are run with ./script will use the old Bash (the scenario in the question). Solutions are:

  • Call the script with bash script: the new Bash will be used. Disadvantage: you always have to call it like that.
  • Change the shebang line to #!/usr/local/bin/bash. Disadvantage: on many systems, there is no Bash in /usr/local/bin and your script isn't portable any longer.
  • Change the shebang line to #!/usr/bin/env bash. This will use the first bash in your PATH, which should be the new one. This is pretty portable; the only downside is that you don't know exactly which Bash will be executed.

See also these Q&A:

Solution 3 - Bash

Here is a Workaround, if you want to use chars as array index with bash v3:

array=(
	'hello::world.'
	'nice::to meet you'
)

for index in "${array[@]}" ; do
	KEY="${index%%::*}"
	VALUE="${index##*::}"
	echo "$KEY - $VALUE"
done

Output:

hello - world.
nice - to meet you

Solution 4 - Bash

Here is how to get the updated bash version on OS X, you should install brew and then bash.

$ /bin/bash --version    
GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin14)
    
$ brew install bash    
... install

$ /usr/local/bin/bash --version    
GNU bash, version 4.3.46(1)-release (x86_64-apple-darwin14.5.0)

Solution 5 - Bash

  1. Check the current shell you are using with this cmd:

     echo $SHELL
    

E.g. it could say /bin/bash

  1. Run --version on that $SHELL:

     /bin/bash --version
    

It may output something like GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin16)

If it is before version 4, you'll have to upgrade.

  1. Check if you already have a bash shell with version 4. Try running:

     bash --version
    

If so, you just need to change your default shell to that shell.

You can use these cmds to do so:

    sudo bash -c 'echo /usr/local/bin/bash >> /etc/shells'
    sudo chsh -s /usr/local/bin/bash

The first adds the shell to the allowed shells. The second actually changes your default shell.

Solution 6 - Bash

meigrafd's answer solved my problem, so if using an incorrect shebang or still on bash version 3 the following allowed me to return a value based on it's associated key:

array=(
    'hello::world.'
    'nice::to meet you'
)

for index in "${array[@]}" ; do
  KEY="${index%%::*}"
  VALUE="${index##*::}"
  if [ "$KEY" == "nice" ]; then
    echo "$VALUE"
    break
  fi
done

This will return the value "to meet you".

Solution 7 - Bash

Old BASH version didn't support declare -A syntax of declaring arrays. I suggest using either of these 2 forms to declare arrays in bash to make it compatible with older bash version of your production system:

arr=( '10' '20' '30' )
echo ${arr[@]}

or

arr[0]=10
arr[1]=20
arr[2]=30
echo ${arr[@]}

Solution 8 - Bash

Nothing above helped me, so I opened /etc/shells and changed the line

  • /bin/bash to /usr/local/bin/bash, and then reloaded it with source /etc/shells and now I can enjoy new possibilities of v4 of bash

Solution 9 - Bash

Per the command:

help declare
declare: declare [-aAfFgilnrtux] [-p] [name[=value] ...]
  Set variable values and attributes.

Declare variables and give them attributes.  If no NAMEs are given,
display the attributes and values of all variables.
Options which are set attributes:
  -a        to make NAMEs indexed arrays (if supported)
  -A        to make NAMEs associative arrays (if supported)

Notice lowercase "-a" and uppercase "-A" are "(if supported)". Also if you look at the posted error message for declare usage:

/script.sh: line 11: declare: -A: invalid option
declare: usage: declare [-afFirtx] [-p] [name[=value] ...]

The given options are "[-afFirtx]" showing to use a lowercase "-a" but no uppercase "-A". Compare that to the usage string from the help command. It looks as if it's just not supported on the given machine.

Solution 10 - Bash

Try using a different shebang. On my Mac:

$ which bash
/usr/local/bin/bash

So, this script runs fine, producing "Hello World":

#!/usr/local/bin/bash
declare -A assoc
assoc[hello]="Hello World"
echo ${assoc[hello]}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJoelView Question on Stackoverflow
Solution 1 - BashRichard HView Answer on Stackoverflow
Solution 2 - BashBenjamin W.View Answer on Stackoverflow
Solution 3 - BashmeigrafdView Answer on Stackoverflow
Solution 4 - BashkhancellView Answer on Stackoverflow
Solution 5 - BashTylerView Answer on Stackoverflow
Solution 6 - BashKeithJView Answer on Stackoverflow
Solution 7 - BashanubhavaView Answer on Stackoverflow
Solution 8 - BashMihey MikView Answer on Stackoverflow
Solution 9 - BashEnterUserNameHereView Answer on Stackoverflow
Solution 10 - BashKhananView Answer on Stackoverflow