关联数组:错误“声明:-A:无效选项”
Posted
技术标签:
【中文标题】关联数组:错误“声明:-A:无效选项”【英文标题】:Associative arrays: error "declare: -A: invalid option" 【发布时间】:2011-08-28 04:56:53 【问题描述】:我在 bash (v 4) 中编写了一个使用关联数组的脚本。
它在我使用 4.1.5(1)-release
的本地机器上运行良好。
在生产机器上,使用 4.1.0(1)-release
声明 assoc 数组的以下行失败:
declare -A uniqjars
带有消息:
/script.sh: line 11: declare: -A: invalid option
declare: usage: declare [-afFirtx] [-p] [name[=value] ...]
我以为这是 bash 4 的一般功能?
在生产机器上的 bash 手册中,它使用-A
进行了讨论,所以我认为它应该工作。
关联数组是使用
declare -A <i>name</i>
.
我可以通过打印出echo 'bash -version
的值来确认脚本使用的是正确版本的bash。
我做错了什么?
【问题讨论】:
我猜,由于某种原因我在机器上从 bash 3 升级到了 4,它正在从 bash3 中获取旧的 declare 函数? 可能是您使用了不正确的 shebang? 【参考方案1】:在使用 Homebrew 安装较新的 Bash 后,以下似乎是 macOS 上的典型场景:
/bin/bash
是旧的 Bash,3.2
/usr/local/bin/bash
是了解关联数组(4.0 或更高版本)的新 Bash
type bash
指向 /usr/local/bin/bash
和 bash --version
是新的(因为它解析为 /usr/local/bin/bash --version
)
但是,使用 ./script
运行的带有 #!/bin/bash
shebang 行的脚本将使用旧的 Bash(问题中的场景)。解决方案是:
bash script
调用脚本:将使用新的 Bash。 缺点:你总是要这样称呼它。
将shebang行更改为#!/usr/local/bin/bash
。 缺点:在许多系统上,/usr/local/bin
中没有 Bash,并且您的脚本不再可移植。
将 shebang 行更改为 #!/usr/bin/env bash
。 这将使用 PATH
中的第一个 bash
,它应该是新的。这是非常便携的;唯一的缺点是您不确切知道将执行哪个 Bash。
另请参阅这些问答:
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? 在 Unix 和 Linux 上【讨论】:
完全在目标上!【参考方案2】:用这个 cmd 检查你当前使用的 shell:
echo $SHELL
例如可以说/bin/bash
在那个$SHELL
上运行--version
:
/bin/bash --version
它可能会输出类似GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin16)
的东西
如果是第 4 版之前,则必须升级。
检查您是否已经有版本 4 的 bash shell。尝试运行:
bash --version
如果是这样,您只需将默认 shell 更改为该 shell。
您可以使用这些 cmd 来执行此操作:
sudo bash -c 'echo /usr/local/bin/bash >> /etc/shells'
sudo chsh -s /usr/local/bin/bash
第一个将 shell 添加到允许的 shell。第二个实际上更改了您的默认 shell。
【讨论】:
它对我有用,只是在第二个命令中没有sudo
(即chsh -s /usr/local/bin/bash
),因为我希望它为我的用户而不是 root 更改它
"/usr/local/bin/bash" 可能已经在 "/etc/shells" 中,所以在无缘无故添加之前检查它并没有什么坏处。使用 sudo 实际上会更改用户 root 的 shell。所以你可能想要执行 chsh 而不是 sudo chsh,或者两者都执行。【参考方案3】:
根据命令:
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)
注意小写“-a”和大写“-A”是“(如果支持)”。另外,如果您查看已发布的错误消息以声明用法:
/script.sh: line 11: declare: -A: invalid option
declare: usage: declare [-afFirtx] [-p] [name[=value] ...]
给定的选项是“[-afFirtx]”,显示使用小写“-a”但不使用大写“-A”。将其与 help 命令中的用法字符串进行比较。看起来好像它在给定的机器上不受支持。
【讨论】:
【参考方案4】:这里是如何在 OS X 上获取更新的bash
版本,你应该安装brew
然后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】:上面没有任何帮助,所以我打开 /etc/shells 并更改了行
- /bin/bash
到 /usr/local/bin/bash
,然后重新加载它
source /etc/shells
现在我可以享受 bash v4 的新可能性了
【讨论】:
【参考方案6】:meigrafd 的回答解决了我的问题,所以如果使用不正确的 shebang 或仍在 bash 版本 3 上,以下允许我根据关联键返回一个值:
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
这将返回值“遇见你”。
【讨论】:
【参考方案7】:尝试使用不同的 shebang。在我的 Mac 上:
$ which bash
/usr/local/bin/bash
所以,这个脚本运行良好,产生了“Hello World”:
#!/usr/local/bin/bash
declare -A assoc
assoc[hello]="Hello World"
echo $assoc[hello]
【讨论】:
【参考方案8】:如果您想在 bash v3 中使用 chars 作为数组索引,这里有一个解决方法:
array=(
'hello::world.'
'nice::to meet you'
)
for index in "$array[@]" ; do
KEY="$index%%::*"
VALUE="$index##*::"
echo "$KEY - $VALUE"
done
输出:
hello - world.
nice - to meet you
【讨论】:
所以看起来这只是拆分字符串,使用::
作为中心 - string='hello::world' && LEFT="$string%%::*" && RIGHT="$string##*::" && echo $LEFT "<>" $RIGHT
- 你仍然无法通过键查找值。
@jgraup 您必须创建一个函数,该函数将循环并返回传递的键的值。如果您不能使用关联数组或想让您的脚本更便携,这是一个很好的解决方法。
我该如何下标呢?【参考方案9】:
旧 BASH 版本不支持 declare -A
声明数组的语法。我建议使用这两种形式中的任何一种在 bash 中声明数组,以使其与生产系统的旧 bash 版本兼容:
arr=( '10' '20' '30' )
echo $arr[@]
或
arr[0]=10
arr[1]=20
arr[2]=30
echo $arr[@]
【讨论】:
【参考方案10】:确保在您的 shell 脚本(#!/bin/bash
或其他)顶部作为解释器调用的 bash 版本也是版本 4。如果您正在这样做:
bash --version
它给你 v4,做一个which bash
来检查它的位置。
【讨论】:
使用which bash
,我发现我没有升级到 bash 4。我使用 this link 升级运行 Lion 的 MacBook Pro 上的版本。 YMMV
Bash 4 for OSX 也可以通过brew 获得。但是,/bin/bash
需要替换为或符号链接到它安装的版本。
echo "$BASH_VERSION"
更有用的是检查正在运行的实例,而不是 PATH 中第一个的版本。
which bash
不如 type bash
准确。 which
对别名、shell 函数、散列查找等一无所知。以上是关于关联数组:错误“声明:-A:无效选项”的主要内容,如果未能解决你的问题,请参考以下文章