Mac BigSur 上的 Bash 脚本语法错误:算术运算符无效

Mac BigSur 上的 Bash 脚本语法错误:算术运算符无效

这里出现一个奇怪的错误。我有一些像这样的 json 结构:

BACKUP_REPOS='''
[
    {"name":"my.server1", "hash":"server1-hash"},
    {"name":"my.server2", "hash":"server2-hash"},
    {"name":"my.server3", "hash":"server3-hash"}
]
'''

我试图做的是基于使用jq以下函数生成一个可选择的菜单:

# generate the server menu
server_menu( ) {

    # hold some arrays
    declare -a _name _hash;

    while read -r _server _pw; do

        # hold the selected item
        _name[$_server]=$_server;
        _hash[$_server]=$_pw;

    # end the loop generation
    done < <( jq -rc '.[] | "\(.name) \(.hash)"' <<< "$BACKUP_REPOS" )

    # now loop the resultset
    select _server in "${!_name[@]}"; do 
        [ -n "$_server" ] && break;
    done;

    # return the server and hash
    SELECTED_SERVER=${_name[$_server]};
    SELECTED_HASH=${_hash[$_server]};

}

现在,这在 Ubuntu 18+ 中工作得很好,但在我的 Mac BigSur 终端上会生成错误。错误是:syntax error: invalid arithmetic operator (error token is ".server1") on line 82,在我的完整代码文件中是这一行:_name[$_server]=$_server;

我这里哪里出错了?此时,我唯一关心的是让这个脚本在我的 Mac 上运行...我可以保留它的多个副本

TIA

答案1

看起来您正在尝试使用关联数组,这在 macOS 附带的默认 bash 版本上是不可能的,因此您必须将 bash 更新到版本 4 或更高版本才能执行此操作,但您还需要更改:

declare -a _name _hash

declare -A _name _hash

作为标准数组,索引中唯一可以包含的内容是整数,并且您可以在其中执行算术扩展,[ ... ]因此它会因您在其中扩展的非整数/无效操作而窒息。

答案2

作为jesse_b 指出,问题是您的数组不是关联数组。 macOS上bash不知道如何处理关联数组,所以考虑重写zsh或者使用普通数组。或者,bash使用 Homebrew 安装更新的 shell 并将其更正declare -adeclare -A.

以下内容适用于bashmacOS 上的默认设置(假设jq也已安装):

menu_select_server () {
        local server_json=file.json  # JSON containing server config

        # Set positional parameters to list of servers
        eval "$( jq -r '[ "set --", (.[].name|@sh) ] | @tsv' "$server_json" )"

        # Select wanted server
        local PS3='Select server: '
        select SELECTED_SERVER; do
                [[ -n $SELECTED_SERVER ]] && break
        done

        # Get corresponding hash
        SELECTED_HASH=$(
                jq -r --argjson i "$REPLY" \
                        '.[($i-1)].hash' "$server_json"
        )
}

我们在这里解析文件两次,一次获取服务器列表,一次获取所选服务器的哈希值,但是很容易做与您正在做的类似的事情,只需切换到使用$REPLY来自select循环获取哈希值:

menu_select_server () {
        local server_json=file.json  # JSON containing server config

        local name hash
        local hashes=()
        set --

        # Read names into list of positional parameters
        # Read hashes into "hashes" array
        while IFS=$'\t' read -r name hash; do
                set -- "$@" "$name"
                hashes+=( "$hash" )
        done < <( jq -r '.[] | [ .name, .hash ] | @tsv' "$server_json" )
        # or:
        #     jq -r 'map([ .name, .hash ] | @tsv)[]' "$server_json"

        # Select wanted server
        local PS3='Select server: '
        select SELECTED_SERVER; do
                [[ -n $SELECTED_SERVER ]] && break
        done

        # Get corresponding hash
        SELECTED_HASH=${hashes[REPLY-1]}
}

相关内容