在bash 3中创建关联数组

mak*_*rek 29 bash

在彻底搜索了一种在bash中创建关联数组的方法后,我发现它declare -A array可以解决这个问题.但问题是,它仅适用于bash版本4,服务器在我们系统中的bash版本是3.2.16.

如何在bash 3中实现某种类似关联数组的hack?这些值将传递给类似的脚本

ARG=array[key];

./script.sh ${ARG}
Run Code Online (Sandbox Code Playgroud)

编辑:我知道我可以在awk或其他工具中执行此操作,但我正在尝试解决的方案需要严格的bash.

Gil*_*il' 30

Bash 3没有关联数组,因此您将不得不使用其他语言功能.请注意,即使在bash 4下,您编写的代码也没有按照您的声明执行操作:./script.sh ${ARG}不会将关联数组传递给子脚本,因为${ARG}ARG关联数组时会扩展为空.您无法将关联数组传递给子进程,无论如何都需要对其进行编码.

您需要在父脚本和子脚本之间定义一些参数传递协议.一个常见的方法是在表单中传递参数key=value.这假定该字符=不出现在键中.

您还需要弄清楚如何在父脚本和子脚本中表示关联数组.他们不需要使用相同的表示.

表示关联数组的常用方法是为每个元素使用单独的变量,并使用通用的命名前缀.这要求密钥名称仅由ASCII字母(任何一种情况),数字和下划线组成.例如,代替${myarray[key]},写${myarray__key}.如果在运行时确定密钥,则首先需要进行一轮扩展:而不是${myarray[$key]}写入

n=myarray__${key}; echo ${!n}
Run Code Online (Sandbox Code Playgroud)

对于作业,请使用printf -v.请注意使用指定值的%s格式printf.不要写,printf -v "myarray__${key}" %s "$value"因为那将$value作为一种格式对待并%在其上执行printf 扩展.

printf -v "myarray__${key}" %s "$value"
Run Code Online (Sandbox Code Playgroud)

如果需要将带有这样表示的关联数组传递给带有key=value参数表示的子进程,则可以使用${!myarray__*}枚举名称以其开头的所有变量myarray__.

args=()
for k in ${!myarray__*}; do
  n=$k
  args+=("$k=${!n}")
done
Run Code Online (Sandbox Code Playgroud)

在子进程中,要将表单的参数转换为key=value带有前缀的单独变量:

for x; do
  if [[ $x != *=* ]]; then echo 1>&2 "KEY=VALUE expected, but got $x"; exit 120; fi
  printf -v "myarray__${x%%=*}" %s "${x#*=}"
done
Run Code Online (Sandbox Code Playgroud)

顺便问一下,你确定这是你需要的吗?您可能希望在子shell中运行子脚本,而不是从另一个bash脚本调用bash脚本.这样它就会继承父母的所有变量.


Bub*_*off 9

以下是使用参数扩展的bash 3及更早版本中关联数组的另一篇文章/解释:https:
//stackoverflow.com/a/4444841

吉尔斯的方法有一个很好的if说法,可以捕捉分隔符问题,消除奇怪的输入......等等.用那个.

如果您对参数扩展有点熟悉:http:
//www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html

在您的场景中使用[如上所述:发送到脚本]:脚本1: sending_array.sh

# A pretend Python dictionary with bash 3 
ARRAY=( "cow:moo"
        "dinosaur:roar"
        "bird:chirp"
        "bash:rock" )

bash ./receive_arr.sh "${ARRAY[@]}"
Run Code Online (Sandbox Code Playgroud)

脚本2: receive_arr.sh

argAry1=("$@")

function process_arr () {
    declare -a hash=("${!1}")
    for animal in "${hash[@]}"; do
        echo "Key: ${animal%%:*}"
        echo "Value: ${animal#*:}"
    done
}

process_arr argAry1[@]

exit 0
Run Code Online (Sandbox Code Playgroud)

方法2,获取第二个脚本:脚本1: sending_array.sh

source ./receive_arr.sh
# A pretend Python dictionary with bash 3 
ARRAY=( "cow:moo"
        "dinosaur:roar"
        "bird:chirp"
        "bash:rock" )

process_arr ARRAY[@]
Run Code Online (Sandbox Code Playgroud)

脚本2: receive_arr.sh

function process_arr () {
    declare -a hash=("${!1}")
    for animal in "${hash[@]}"; do
        echo "Key: ${animal%%:*}"
        echo "Value: ${animal#*:}"
    done
}
Run Code Online (Sandbox Code Playgroud)

参考:
在bash中将数组作为参数传递


Llo*_*eki 5

如果您不想处理大量变量,或者键只是无效的变量标识符,并且您的数组保证少于 256 项,则可以滥用函数返回值。此解决方案不需要任何子shell,因为该值可以作为变量随时可用,也不需要任何迭代,因此性能会大打折扣。它也非常易读,几乎就像 Bash 4 版本。

这是最基本的版本:

hash_index() {
    case $1 in
        'foo') return 0;;
        'bar') return 1;;
        'baz') return 2;;
    esac
}

hash_vals=("foo_val"
           "bar_val"
           "baz_val");

hash_index "foo"
echo ${hash_vals[$?]}
Run Code Online (Sandbox Code Playgroud)

此答案中的更多详细信息和变体