问题
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?
回答1:
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.
回答2:
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
回答3:
The following seems to be a typical scenario on macOS after installing a newer Bash with Homebrew:
/bin/bashis the old Bash, 3.2/usr/local/bin/bashis the new Bash that knows about associative arrays (4.0 or newer)type bashpoints to/usr/local/bin/bashandbash --versionis 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/binand your script isn't portable any longer. - Change the shebang line to
#!/usr/bin/env bash. This will use the firstbashin yourPATH, 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:
- What is the difference between "#!/usr/bin/env bash" and "#!/usr/bin/bash"?
- Why is #!/usr/bin/env bash superior to #!/bin/bash?
- Why is it better to use “#!/usr/bin/env NAME” instead of “#!/path/to/NAME” as my shebang? on Unix & Linux
回答4:
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)
回答5:
Check the current shell you are using with this cmd:
echo $SHELLE.g. it could say
/bin/bashRun
--versionon that$SHELL:/bin/bash --versionIt 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.
Check if you already have a bash shell with version 4. Try running:
bash --versionIf 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/bashThe first adds the shell to the allowed shells. The second actually changes your default shell.
回答6:
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".
回答7:
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
回答8:
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[@]}
回答9:
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.
回答10:
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]}
来源:https://stackoverflow.com/questions/6047648/bash-4-associative-arrays-error-declare-a-invalid-option