【问题标题】:Associative arrays: error "declare: -A: invalid option"关联数组:错误“声明:-A:无效选项”
【发布时间】: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?

标签: bash associative-array


【解决方案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。

另请参阅这些问答:

【讨论】:

  • 完全在目标上!
【解决方案2】:
  1. 用这个 cmd 检查你当前使用的 shell:

    echo $SHELL
    

    例如可以说/bin/bash

  2. 在那个$SHELL上运行--version

    /bin/bash --version
    

    它可能会输出类似GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin16)的东西

    如果是第 4 版之前,则必须升级。

  3. 检查您是否已经有版本 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 函数、散列查找等一无所知。
              猜你喜欢
              • 1970-01-01
              • 2010-11-12
              • 1970-01-01
              • 1970-01-01
              • 2021-10-31
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多