bash单维数组限制的更简洁的解决方法

时间:2016-09-28 10:44:55

标签: bash

与ksh相反,它允许多维数组,bash(4.2或更低版本)不允许多维数组。 我通过在元素中使用分隔符来解决这个问题,然后第一个数组的每个元素都可以自己制作成数组。 敌人的例子:

GPIO=("in:down:0:22:1-1.4:17:usb:usb port 3 mgmt button"
"in:down:0:13:1-1.5:18:usb:usb port 4 mgmt button")

然后访问第一行的第三个元素我会做这样的事情:

eval $(echo "ROW0=($(echo "${GPIO[0]}" | awk -F: '{ for(i=1;i<=NF;i++) printf("\"%s\" ",$i);}' ))")
echo ${ROW0[2]}

我不喜欢这样做,但我没有找到解决问题的更简洁方法。 是否有一个更整洁,更有效的解决问题的方法,同时仍然像阵列一样接近它?

还有一种解决方法,使用关联数组并在元素索引中添加假的第二个索引:

declare -A FAKE2DIMARRAY
FAKE2DIMARRAY=(
[0,0]="first row first element"
[0,1]="first row second element"
[1,0]="second row first element"
[1,1]="second row second element"
)

虽然这个解决方案非常简洁有效,但如果它有很多行和元素,它会使数组的定义变得混乱。 例如,我的完整GPIO阵列实际上是16x8,这需要128行并注意正确索引每一行...在这种情况下,这也不是最优的。

1 个答案:

答案 0 :(得分:2)

自动创建(假的)多维fullarray并不困难。要从数组中提取索引:请查看结尾。

现在使用字符串创建多个数组:

IFS=: read -a arr0 <<<"in:down:0:22:1-1.4:17:usb:usb port 3 mgmt button"
IFS=: read -a arr1 <<<"in:down:0:13:1-1.5:18:usb:usb port 4 mgmt button"

在这个示例中,只需使用相同名称arr开头即可。

然后,自动系统将采用名称以arr开头的所有变量作为行 并且这些数组中的值计数为列:

#!/bin/bash
IFS=: read -a row1 <<<"in:down:0:22:1-1.4:17:usb:usb port 3 mgmt button"
IFS=: read -a row2 <<<"in:down:0:13:1-1.5:18:usb:usb port 4 mgmt button"

#echo "one ${row1[@]}"
#echo "two ${row2[@]}"

declare -A fullarray
# Note that ${!row*} lists all the variables that start with arr.
for hrow in ${!row*}; do
    #echo "row $hrow"
    for (( column=0; column<${#row1[@]}; column++ )); do
        #echo "column $column"
        indirect=$hrow[$column]
        #echo "indirect $indirect ${!indirect}"
        fullarray[${hrow#row},$column]=${!indirect}
    done
done

declare -p "fullarray"

取消注释回显以查看数组是如何构建的。

declare -p fullarray的输出中可以看出,变量具有数组中的所有值(hrow,column),如果行和列是来自的数字,则可以使用fullarray[$hrow,$column]访问每个值0及以上。
在这种情况下,将$保留在变量中,因为我们需要索引的字符串表示(而不是它们的数字等价物)。

当然,我想对每行数组的赋值已经解决了你的问题而无需使用awk。

这仅取决于使用:

indirect=arr$row[$column]
${!indirect}

对你来说已经足够了。 : - )

要从完整数组中提取索引,如果需要,可以分三步完成。首先从fullarray获取所有索引:

allind=(${!fullarray})

而且,由于allind本身就是一个数组,你可以使用逗号作为分隔符来提取每个部分:

rowind=( ${allind[@]//,*} )

由于rowind将包含所有列的所有行索引,因此将重复这些值。只需排序并删除重复:

rowind=( $(printf '%s\n' "${rowind[@]}"|sort -u) )

并且,如果需要,请查看行索引的定义:

declare -p rowind

列的相同过程(除了已定义allind):

allind=(${!fullarray[@]})
columnind=( ${allind[@]//*,} )
columnind=( $(printf '%s\n' "${columnind[@]}"|sort -u) )
declare -p columnind