如何在bash中声明2D数组

Ani*_*ack 69 linux bash shell

我想知道如何在bash中声明一个2D数组然后初始化为0.

在C中它看起来像这样:

int a[4][5] = {0};
Run Code Online (Sandbox Code Playgroud)

我如何为元素赋值?如在C:

a[2][3] = 3;
Run Code Online (Sandbox Code Playgroud)

jm6*_*666 62

您可以使用哈希模拟它们,但需要关注前导零和许多其他事情.下一个演示工作,但它远非最佳解决方案.

#!/bin/bash
declare -A matrix
num_rows=4
num_columns=5

for ((i=1;i<=num_rows;i++)) do
    for ((j=1;j<=num_columns;j++)) do
        matrix[$i,$j]=$RANDOM
    done
done

f1="%$((${#num_rows}+1))s"
f2=" %9s"

printf "$f1" ''
for ((i=1;i<=num_rows;i++)) do
    printf "$f2" $i
done
echo

for ((j=1;j<=num_columns;j++)) do
    printf "$f1" $j
    for ((i=1;i<=num_rows;i++)) do
        printf "$f2" ${matrix[$i,$j]}
    done
    echo
done
Run Code Online (Sandbox Code Playgroud)

上面的例子创建了一个带有随机数的4x5矩阵,并将其打印出来,并带有示例结果

           1         2         3         4
 1     18006     31193     16110     23297
 2     26229     19869      1140     19837
 3      8192      2181     25512      2318
 4      3269     25516     18701      7977
 5     31775     17358      4468     30345
Run Code Online (Sandbox Code Playgroud)

原则是:创建一个关联数组,其中索引是一个字符串3,4.好处:

  • 它可以用于任何维度的数组;)像:30,40,23维.
  • 语法接近"C",就像数组一样 ${matrix[2,3]}

  • 这种方法的明显缺点是无法知道尺寸的长度.尽管如此,它在大多数其他场景中都很有效!谢谢!! (2认同)

Sir*_*hos 23

Bash不支持多维数组.

您可以使用间接扩展来模拟它:

#!/bin/bash
declare -a a0=(1 2 3 4)
declare -a a1=(5 6 7 8)
var="a1[1]"
echo ${!var}  # outputs 6
Run Code Online (Sandbox Code Playgroud)

使用此方法也可以进行分配:

let $var=55
echo ${a1[1]}  # outputs 55
Run Code Online (Sandbox Code Playgroud)

编辑1:要从文件中读取此类数组,行中的每一行以及由空格分隔的值,请使用以下命令:

idx=0
while read -a a$idx; do
    let idx++;
done </tmp/some_file
Run Code Online (Sandbox Code Playgroud)

编辑2:要声明初始化a0..a3[0..4]0,您可以运行:

for i in {0..3}; do
    eval "declare -a a$i=( $(for j in {0..4}; do echo 0; done) )"
done
Run Code Online (Sandbox Code Playgroud)


Jah*_*hid 22

Bash没有多维数组.但您可以使用关联数组模拟一些类似的效果.以下是假装用作多维数组的关联数组的示例:

declare -A arr
arr[0,0]=0
arr[0,1]=1
arr[1,0]=2
arr[1,1]=3
echo "${arr[0,0]} ${arr[0,1]}" # will print 0 1
Run Code Online (Sandbox Code Playgroud)

如果未将数组声明为关联(with -A),则上述操作无效.例如,如果省略该declare -A arr行,echo则将打印2 3而不是0 1,因为0,0,1,0这将被视为算术表达式并计算为0(逗号运算符右侧的值).


ras*_*hok 7

2D 数组可以在 bash 中通过声明 1D 数组来实现,然后可以使用 访问元素(r * col_size) + c)。下面的逻辑删除一维数组 ( str_2d_arr) 并打印为二维数组。

col_size=3
str_2d_arr=()
str_2d_arr+=('abc' '200' 'xyz')
str_2d_arr+=('def' '300' 'ccc')
str_2d_arr+=('aaa' '400' 'ddd')

echo "Print 2D array"
col_count=0
for elem in ${str_2d_arr[@]}; do
    if [ ${col_count} -eq ${col_size} ]; then
        echo ""
        col_count=0
    fi
    echo -e "$elem \c"
    ((col_count++))
done
echo ""
Run Code Online (Sandbox Code Playgroud)

输出是

Print 2D array
abc 200 xyz 
def 300 ccc
aaa 400 ddd
Run Code Online (Sandbox Code Playgroud)

下面的逻辑对于从上面声明的一维数组中获取每一行非常有用str_2d_arr

# Get nth row and update to 2nd arg
get_row_n()
{
    row=$1
    local -n a=$2
    start_idx=$((row * col_size))
    for ((i = 0; i < ${col_size}; i++)); do
        idx=$((start_idx + i))
        a+=(${str_2d_arr[${idx}]})
    done
}

arr=()
get_row_n 0 arr
echo "Row 0"
for e in ${arr[@]}; do
    echo -e "$e \c"
done
echo ""
Run Code Online (Sandbox Code Playgroud)

输出是

Row 0
abc 200 xyz
Run Code Online (Sandbox Code Playgroud)


Mag*_*ero 5

您也可以以更智能的方式解决这个问题

q=()
q+=( 1-2 )
q+=( a-b )

for set in ${q[@]};
do
echo ${set%%-*}
echo ${set##*-}
done
Run Code Online (Sandbox Code Playgroud)

当然,22线解决方案或间接可能是更好的方法,为什么不在每个地方撒上eval.


Ste*_*uan 5

另一种方法是您可以将每一行表示为字符串,即将2D数组映射到1D数组。然后,您需要做的就是在进行编辑时解包并重新打包行的字符串:

# Init a 4x5 matrix
a=("0 0 0 0 0" "0 0 0 0 0" "0 0 0 0 0" "0 0 0 0 0")

aset() {
    row=$1
    col=$2
    value=$3
    IFS=' ' read -r -a tmp <<< "${a[$row]}"
    tmp[$col]=$value
    a[$row]="${tmp[@]}"
}

# Set a[2][3] = 3
aset 2 3 3

# Show result
for r in "${a[@]}"; do
  echo $r
done
Run Code Online (Sandbox Code Playgroud)

输出:

0 0 0 0 0
0 0 0 0 0
0 0 0 3 0
0 0 0 0 0
Run Code Online (Sandbox Code Playgroud)