2

I have an associative array of dotfile names to ids that looks exactly like this:

declare -A ids=(
  [".steve"]="1 4 5 6 10"
  [".john"]="3 4 5 1 11"
  ...
)

When I run this code I get:

./declare_ids.sh: line 23: .steve: operand expected (error token is ".steve")

This error seems really, really vague. I don't understand what is going on. I'm pretty new to bash and have just been learning about associative arrays in bash v4. Could anyone help?

EDIT:

The shebang line in this script is #!/bin/bash. I am running this inside of a zsh terminal on OS X, and I installed bash via brew install bash.

bash --version says:

GNU bash, version 4.4.12(1)-release (x86_64-apple-darwin15.6.0)                                                                                                │
Copyright (C) 2016 Free Software Foundation, Inc.                                                                                                              │
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>                                                                                  │
                                                                                                                                                               │
This is free software; you are free to change and redistribute it.                                                                                             │
There is NO WARRANTY, to the extent permitted by law.

This is also the case when I put bash --version immediately before the declare -A line.

and which bash returns /usr/local/bin/bash. The script is invoked inside the terminal simply by typing ./declare_ids.sh.

EDIT AGAIN:

As it has already been said echoing $BASH_VERSION is different than bash --version. $BASH_VERSION is 3.2.57(1)-release.

Is there a way to make /bin/bash upgraded? I use this script on a ubuntu circleCI box as well, so anything hardcoded to what brew does would be bad.

  • 1
    The command `bash --version` starts a new instance of bash and returns its version. To find the version of bash that the script is running under, add the command `echo $BASH_VERSION` and show us the result. – John1024 May 13 '17 at 01:00
  • Your she-bang line says `/bin/bash`. If `which bash` says `/usr/local/bin/bash`, then that is (probably) a different bash version. – rici May 13 '17 at 01:02
  • You can compare `/bin/bash --version` (what the script runs, likely old Bash) and `/usr/local/bin/bash --version`, likely new Bash. Running the script with `bash ./script` uses new Bash, running it `./script` uses old Bash. That's my guess. – Benjamin W. May 13 '17 at 01:23
  • @John1024 great catch, updated my response. –  May 13 '17 at 01:25
  • I'm voting to close this as a duplicate, but the answer I would have given here was missing, so I added it there. – Benjamin W. May 13 '17 at 02:05

1 Answers1

2

The most likely explanation is that your bash version is too old to implement associative arrays, which might be the case if you are using the default version from OS X, for example.

Get a definitive version for the running bash by placing the command:

echo $BASH_VERSION

immediately before the declare -A. (You could also use the command /path/to/bash --version, where /path/to/bash is the full path in the shebang line; in this case /bin/bash)

It's true that the error message is not very easy to interpret, but it would require time travel for the old version to be able to tell you that you were using a syntax which hadn't yet been added to the shell. The error comes from the declare built-in interpreting the parenthesized argument as an indexed array, which it will automatically do if it sees var=(, even without the -a option. In an indexed array, subscripts must be numeric (integers, in bash terms) and [.steve] is not numeric. (The quotes are irrelevant; ["3"] would work fine because bash lets you quote numbers in numeric expressions. Curiously, [steve] would also work fine, because in a numeric expression a variable name which is not a defined variable is treated as 0.)

rici
  • 234,347
  • 28
  • 237
  • 341
  • Thank you for your reply. As I said above I am running bash version 4, 4.4.2 exactly, and it supports associative arrays. –  May 13 '17 at 00:45
  • 1
    @rec, you may have a bash version 4, but that error message doesn't come from it. It comes from version 3. So that implies that you also have version 3 installed. Perhaps `sh` is resolved to version 3; perhaps you have the wrong path in your she-bang line. More details on how you invoke the script would help. – rici May 13 '17 at 00:50
  • @rec: updated with some suggestions about how to verify the version being run for the script in question. – rici May 13 '17 at 00:52
  • I added more details as requested. –  May 13 '17 at 00:55
  • @rec: `bash --version` will be the same regardless of which shell you are running, but `echo $BASH_VERSION` is the version of the running shell. Hopefully it is clear why this is the case. (However, you might want to try the one in the shebang: `/bin/bash --version`.) – rici May 13 '17 at 00:59
  • I'm also using `GNU bash, version 4.4.12(1)-release (x86_64-apple-darwin16.3.0)` but `/bin/bash` is `GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin16)` so the standard Mac OS bash. – David Ongaro May 13 '17 at 01:14
  • @DavidOngaro is there a way to make `/bin/bash` point to the brew installed one? –  May 13 '17 at 01:26
  • 1
    `#!/usr/bin/env bash`? See https://stackoverflow.com/questions/16365130/the-difference-between-usr-bin-env-bash-and-usr-bin-bash#" – Benjamin W. May 13 '17 at 01:27
  • @rec /bin/bash is protected by [System Integrity Protection](https://support.apple.com/en-us/HT204899); there's no (reasonable) way to upgrade it. Start your script with `#!/usr/bin/env bash` or `#!/usr/local/bin/bash` instead. – Gordon Davisson May 13 '17 at 01:30
  • @BenjaminW. Answered it first - and it did indeed fix it. I wish I could award points to everyone here because I learned so much. BenjaminW. if you could put that in an answer I will award you the points. –  May 13 '17 at 01:31
  • I'm actually almost sure it's a duplicate question, let me check. – Benjamin W. May 13 '17 at 01:34
  • I would say it's a duplicate question of this one: http://stackoverflow.com/questions/6047648/bash-4-associative-arrays-error-declare-a-invalid-option But the env answer is missing, so I'll add it there. – Benjamin W. May 13 '17 at 01:37
  • Just in case, `shebang` is generally used only when executing the script via kernel itself (e.g. `./script.sh`; i.e. `execve()`), and not via Bash which basically ignores it as a comment. Related: https://www.in-ulm.de/~mascheck/various/shebang , https://stackoverflow.com/q/3009192/5113030 (*How does the #! shebang work?*...) – Artfaith Oct 14 '22 at 09:25