关联数组:错误“声明:-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/bashbash --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' &amp;&amp; LEFT="$string%%::*" &amp;&amp; RIGHT="$string##*::" &amp;&amp; echo $LEFT "&lt;&gt;" $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:无效选项”的主要内容,如果未能解决你的问题,请参考以下文章

从 CSV 提供错误的数组关联以导入 mysql

从 belongs_to 关联中获取字段数组?

关联数组

php判断数组是关联数组还是数值数组

关联数组VS索引数组

PHP 数组中的每个ID键关联一个值,可不可以关联两个值?