针对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]}
我不喜欢做这件事,但我还没有找到一个更好的解决这个问题的方法。是否有一种更整洁、更有效的方法来解决这个问题,同时仍然像数组一样接近它?

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

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行,并注意正确索引每行……在这种情况下,这也不是最优的

自动创建(假的)多维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"

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

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


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

这只取决于是否使用:

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

对你来说足够好了。: -)


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

中获取所有索引
allind=(${!fullarray})

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

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

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

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

如果您愿意,还可以查看行索引的定义:

declare -p rowind

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

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

最新更新