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でこのスクリプトを実行することです。複数のコピーを保存できます。

ティア

答え1

macOSに付属のデフォルトのbashバージョンでは、不可能な連想配列を使用したいようです。したがって、これを行うにはbashをバージョン4以降に更新する必要がありますが、次の点も変更する必要があります。

declare -a _name _hash

到着

declare -A _name _hash

標準配列としてインデックスに含めることができる唯一の項目は整数であり、算術拡張を実行できるため、拡張する整数ではなく[ ... ]/誤った演算のために窒息します。

答え2

〜のようにjesse_bが指摘しました、問題は、配列が連想配列ではないということです。 macOSで連想配列を処理する方法がわからないため、通常のbash配列zshを再構築または使用することをお勧めします。または、bashHomebrewを使用して更新されたシェルをインストールしdeclare -aますdeclare -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"
        )
}

ここでは、ファイルを2回解析します。一度はサーバーのリストを取得し、一度は選択したサーバーのハッシュを取得します。ただし、実行している作業と同様の作業を実行するのは簡単です。以下を使用してハッシュをインポートに切り替え$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]}
}

関連情報