关联数组:错误“声明:-A:无效选项”


67

我已经编写了一个在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 name

我可以通过打印出值来确认脚本使用的是正确的bash版本。 echo 'bash -version

我可能做错了什么?


1
我猜想由于某种原因我从机器上的bash 3升级到4,所以它是从bash3拾取旧的声明函数的?
乔尔

3
可能是您使用的Shebang不正确吗?
freethinker

Answers:


44

确保在shell脚本(#!/bin/bash或其他任何东西)顶部作为解释器调用的bash版本也为版本4。

bash --version

它给您v4,请执行awhich bash检查其位置。


1
使用which bash,发现没有升级到bash4。我使用此链接在运行Lion的MacBook Pro上升级了版本。YMMV
AWrightIV

4
也可以通过brew获得OSX的Bash 4 。但是,/bin/bash将需要用它安装的版本代替它或与其符号链接。
汤姆·斯威尼

2
echo "$BASH_VERSION"对于检查正在运行的实例(而不是PATH中第一个实例的版本)更有用。
查尔斯·达菲,

which bash的准确性不如type bashwhich对别名,shell函数,哈希查找等一无所知
Charles Duffy

38

如果您想在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

1
这样看来,它只是将字符串::作为中心进行了分割string='hello::world' && LEFT="${string%%::*}" && RIGHT="${string##*::}" && echo $LEFT "<>" $RIGHT--您仍然无法通过键查找值。
jgraup

@jgraup,您将必须创建一个将循环循环并返回所传递键值的函数。如果您不能使用关联数组或想使脚本更具可移植性,那么这是一个不错的解决方法。
伊兹密尔·拉米雷斯

我怎么下标呢?
亲爱的

35

在使用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

但是,#!/bin/bash运行带有shebang行的脚本./script将使用旧的Bash(问题中的方案)。解决方案是:

  • 使用以下命令调用脚本bash script:将使用新的Bash。缺点:您总是必须这样称呼它。
  • 将shebang行更改为#!/usr/local/bin/bash缺点:在许多系统上,没有Bash/usr/local/bin且您的脚本不再可移植。
  • 将shebang行更改为#!/usr/bin/env bash这将使用第一个bash在你的PATH,这应该是新的。这是非常可移植的。唯一的缺点是您不完全知道将执行哪个Bash。

另请参阅以下问答:


正好在目标上!
sjsam

11

这是bash在OS X上获取更新版本的方法,您应该先安装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)

9
  1. 使用此cmd检查当前使用的shell:

    echo $SHELL
    

    例如,它可以说 /bin/bash

  2. 运行--version$SHELL

    /bin/bash --version
    

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

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

  3. 检查您是否已经拥有版本4的bash shell。尝试运行:

    bash --version
    

    如果是这样,您只需要将默认外壳程序更改为该外壳程序即可。

    您可以使用以下cmd来这样做:

    sudo bash -c 'echo /usr/local/bin/bash >> /etc/shells'
    sudo chsh -s /usr/local/bin/bash
    

    第一个将外壳添加到允许的外壳中。第二个实际上更改了您的默认外壳。


它的工作对我来说只是没有sudo在第二个命令(即chsh -s /usr/local/bin/bash),因为我希望它改变了我的用户,而不是根
威亚的Eyal

8

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

这将返回值“满足您”。


3

上面没有任何帮助,所以我打开了/ etc / shells并将行更改/bin/bash/usr/local/bin/bash,然后重新加载 source /etc/shells,现在我可以享受bash v4的新可能性


2

BASH的旧版本不支持declare -A声明数组的语法。我建议使用以下两种形式之一在bash中声明数组,以使其与生产系统的较早bash版本兼容:

arr=( '10' '20' '30' )
echo ${arr[@]}

要么

arr[0]=10
arr[1]=20
arr[2]=30
echo ${arr[@]}

1

根据命令:

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命令中的用法字符串进行比较。似乎只是给定机器不支持它。


0

尝试使用其他shebang。在我的Mac上:

$ which bash
/usr/local/bin/bash

因此,此脚本运行良好,产生了“ Hello World”:

#!/usr/local/bin/bash
declare -A assoc
assoc[hello]="Hello World"
echo ${assoc[hello]}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.