2013-05-10 99 views
59

我想知道如何在bash声明一个二维数组,然后初始化为0如何申报在bash二维数组

在C它看起来像这样:

int a[4][5] = {0}; 

,我如何给元素赋值?如C:

a[2][3] = 3; 
+2

相关:[多维在bash阵列(http://stackoverflow.com/q/11233825/2533433) – Izzy 2014-11-06 15:14:07

+2

顺便说一句多维数组实际上是(深处)一维数组,处理有点不同,尤其是当涉及到acce时选择它的元素。例如,3×4矩阵有12个单元。你用一个3步的外部循环遍历的“行”和你用内部循环遍历的“列”步骤为1。 – rbaleksandar 2015-06-07 20:49:27

回答

49

您可以模拟它们例如用哈希,但需要对前导零和许多其他的事情照顾。下一个演示很有用,但它远非最佳解决方案。

#!/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 

上述示例创建随机数的4×5矩阵,并打印换位,与实施例导致

  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 

的原理是:创建一个关联数组,其中索引是象3,4一个字符串。好处:

  • 它可以用于任何维数组;例如:30,40,2 3维。
  • 语法是接近“C”状阵列${matrix[2,3]}
+1

这种方法的明显缺点是不能确定尺寸的长度。尽管如此,它在大多数其他情况下效果很好!谢谢!! – 2013-12-13 09:37:55

+0

请你解释一下'f1'和'f2'的作用? – Jodes 2016-10-06 10:03:53

+0

@Jodes“f1”和“f2”包含'printf'的格式,用于精确对齐的打印。它可以被硬编码,例如'printf“%2s”'但使用变量更加灵活 - 就像上面的'f1'一样。 *行号*的“宽度”被计算为“$ num_rows”变量的长度 - 例如,如果'$ num_rows'的行数是9,它的长度是'1',那么格式将是'1 + 1',因此'%2s'。对于'$ num_rows' 2500,它的长度是'4',因此格式将是'%5s' - 等等...... – jm666 2016-10-06 13:51:17

22

Bash不支持多维数组。

可以通过使用间接膨胀虽然模拟它:

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

分配也是可能用这种方法:

let $var=55 
echo ${a1[1]} # outputs 55 

编辑1:为了从文件中读取这样的阵列,每行放在一行上,数值由空格分隔,使用:

idx=0 
while read -a a$idx; do 
    let idx++; 
done </tmp/some_file 

编辑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 
+0

你能演示如何从文件中填充上述“2d阵列模拟” -表?例如有一个随机行数的文件,每行包含5个空格分隔的数字。 – kobame 2013-05-10 18:29:53

+0

@kobame:我编辑了答案,为您提出的问题提供了解决方案。它将读取具有可变行数和可变列数的2d数组,并将其写入a0,a1等。 – 2013-05-10 22:40:54

+0

您将如何使用其他分隔符,如逗号或制表符? – MountainX 2016-07-19 21:30:28

3

您也可以在一个更聪明的方式

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

for set in ${q[@]}; 
do 
echo ${set%%-*} 
echo ${set##*-} 
done 
当然

22线溶液或间接接近这可能是更好的要走的路,为什么不撒洒eval每到哪里。

+0

22行解决方案在哪里使用间接?对于您的解决方案,在编写需要I/O的脚本并且用户希望将'-'输入到'数组'中时,您将要做什么。此外,如果你想模拟一个数组可能更有意义'echo $ {set // - /}'而不是你的两个。 – BroSlow 2014-06-25 01:23:18

+0

这是我错过了我错过了或。我认为$ {set // - /}可能是更好的方式(我不知道%%和##的可移植性问题,尽管我相信你)。如果这是一个非常危险的问题,如果你问了很多次,你会发现你需要A.I.对于你的选择解析器:{p – Prospero 2014-06-25 01:27:59

18

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 

如果不声明数组作为关联(与-A),以上将不起作用。例如,如果省略declare -A arr行,则echo将打印2 3而不是0 1,因为0,0,1,0等将作为算术表达式并评估为0(逗号运算符右侧的值)。

3

来模拟在bash阵列A的方式(它可以适用于任何数量的阵列的维):

#!/bin/bash 

## The following functions implement vectors (arrays) operations in bash: 
## Definition of a vector <v>: 
##  v_0 - variable that stores the number of elements of the vector 
##  v_1..v_n, where n=v_0 - variables that store the values of the vector elements 

VectorAddElementNext() { 
# Vector Add Element Next 
# Adds the string contained in variable $2 in the next element position (vector length + 1) in vector $1 

    local elem_value 
    local vector_length 
    local elem_name 

    eval elem_value=\"\$$2\" 
    eval vector_length=\$$1\_0 
    if [ -z "$vector_length" ]; then 
     vector_length=$((0)) 
    fi 

    vector_length=$((vector_length + 1)) 
    elem_name=$1_$vector_length 

    eval $elem_name=\"\$elem_value\" 
    eval $1_0=$vector_length 
} 

VectorAddElementDVNext() { 
# Vector Add Element Direct Value Next 
# Adds the string $2 in the next element position (vector length + 1) in vector $1 

    local elem_value 
    local vector_length 
    local elem_name 

    eval elem_value="$2" 
    eval vector_length=\$$1\_0 
    if [ -z "$vector_length" ]; then 
     vector_length=$((0)) 
    fi 

    vector_length=$((vector_length + 1)) 
    elem_name=$1_$vector_length 

    eval $elem_name=\"\$elem_value\" 
    eval $1_0=$vector_length 
} 

VectorAddElement() { 
# Vector Add Element 
# Adds the string contained in the variable $3 in the position contained in $2 (variable or direct value) in the vector $1 

    local elem_value 
    local elem_position 
    local vector_length 
    local elem_name 

    eval elem_value=\"\$$3\" 
    elem_position=$(($2)) 
    eval vector_length=\$$1\_0 
    if [ -z "$vector_length" ]; then 
     vector_length=$((0)) 
    fi 

    if [ $elem_position -ge $vector_length ]; then 
     vector_length=$elem_position 
    fi 

    elem_name=$1_$elem_position 

    eval $elem_name=\"\$elem_value\" 
    if [ ! $elem_position -eq 0 ]; then 
     eval $1_0=$vector_length 
    fi 
} 

VectorAddElementDV() { 
# Vector Add Element 
# Adds the string $3 in the position $2 (variable or direct value) in the vector $1 

    local elem_value 
    local elem_position 
    local vector_length 
    local elem_name 

    eval elem_value="$3" 
    elem_position=$(($2)) 
    eval vector_length=\$$1\_0 
    if [ -z "$vector_length" ]; then 
     vector_length=$((0)) 
    fi 

    if [ $elem_position -ge $vector_length ]; then 
     vector_length=$elem_position 
    fi 

    elem_name=$1_$elem_position 

    eval $elem_name=\"\$elem_value\" 
    if [ ! $elem_position -eq 0 ]; then 
     eval $1_0=$vector_length 
    fi 
} 

VectorPrint() { 
# Vector Print 
# Prints all the elements names and values of the vector $1 on sepparate lines 

    local vector_length 

    vector_length=$(($1_0)) 
    if [ "$vector_length" = "0" ]; then 
     echo "Vector \"$1\" is empty!" 
    else 
     echo "Vector \"$1\":" 
     for ((i=1; i<=$vector_length; i++)); do 
      eval echo \"[$i]: \\\"\$$1\_$i\\\"\" 
      ###OR: eval printf \'\%s\\\n\' \"[\$i]: \\\"\$$1\_$i\\\"\" 
     done 
    fi 
} 

VectorDestroy() { 
# Vector Destroy 
# Empties all the elements values of the vector $1 

    local vector_length 

    vector_length=$(($1_0)) 
    if [ ! "$vector_length" = "0" ]; then 
     for ((i=1; i<=$vector_length; i++)); do 
      unset $1_$i 
     done 
     unset $1_0 
    fi 
} 

################## 
### MAIN START ### 
################## 

## Setting vector 'params' with all the parameters received by the script: 
for ((i=1; i<=$#; i++)); do 
    eval param="\${$i}" 
    VectorAddElementNext params param 
done 

# Printing the vector 'params': 
VectorPrint params 

read temp 

## Setting vector 'params2' with the elements of the vector 'params' in reversed order: 
if [ -n "$params_0" ]; then 
    for ((i=1; i<=$params_0; i++)); do 
     count=$((params_0-i+1)) 
     VectorAddElement params2 count params_$i 
    done 
fi 

# Printing the vector 'params2': 
VectorPrint params2 

read temp 

## Getting the values of 'params2'`s elements and printing them: 
if [ -n "$params2_0" ]; then 
    echo "Printing the elements of the vector 'params2':" 
    for ((i=1; i<=$params2_0; i++)); do 
     eval current_elem_value=\"\$params2\_$i\" 
     echo "params2_$i=\"$current_elem_value\"" 
    done 
else 
    echo "Vector 'params2' is empty!" 
fi 

read temp 

## Creating a two dimensional array ('a'): 
for ((i=1; i<=10; i++)); do 
    VectorAddElement a 0 i 
    for ((j=1; j<=8; j++)); do 
     value=$((8 * (i - 1) + j)) 
     VectorAddElementDV a_$i $j $value 
    done 
done 

## Manually printing the two dimensional array ('a'): 
echo "Printing the two-dimensional array 'a':" 
if [ -n "$a_0" ]; then 
    for ((i=1; i<=$a_0; i++)); do 
     eval current_vector_lenght=\$a\_$i\_0 
     if [ -n "$current_vector_lenght" ]; then 
      for ((j=1; j<=$current_vector_lenght; j++)); do 
       eval value=\"\$a\_$i\_$j\" 
       printf "$value " 
      done 
     fi 
     printf "\n" 
    done 
fi 

################ 
### MAIN END ### 
################ 
4

另一种方法是可以代表每一行作为一个字符串,即映射的2D阵列成一维数组。然后,所有你需要做的是解包和重新包装行的字符串,只要你做了编辑:

# 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") 

function aset { 
    IFS=' ' read -r -a tmp <<< "${a[$1]}" 
    tmp[$2]=$3 
    a[$1]="${tmp[@]}" 
} 

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

# Show result 
for r in "${a[@]}"; do 
    echo $r 
done 

输出:

0 0 0 0 0 
0 0 0 0 0 
0 0 0 3 0 
0 0 0 0 0 
1

可以简单地定义两个函数写($ 4是分配的值)并使用任意名称($ 1)和索引($ 2和$ 3)来读取一个使用eval和间接引用的矩阵。

#!/bin/bash 

matrix_write() { 
eval $1"_"$2"_"$3=$4 
# aux=$1"_"$2"_"$3   # Alternative way 
# let $aux=$4    # --- 
} 

matrix_read() { 
aux=$1"_"$2"_"$3 
echo ${!aux} 
} 

for ((i=1;i<10;i=i+1)); do 
for ((j=1;j<10;j=j+1)); do 
    matrix_write a $i $j $[$i*10+$j] 
done 
done 

for ((i=1;i<10;i=i+1)); do 
for ((j=1;j<10;j=j+1)); do 
    echo "a_"$i"_"$j"="$(matrix_read a $i $j) 
done 
done 
+2

嗨,请在代码中添加一些解释,因为它有助于理解你的代码。只有代码答案是不被接受的。 – 2016-09-10 18:17:13

1

如果矩阵的每一行都是相同的大小,那么你可以简单地使用线性数组和乘法。

也就是说,

a=() 
for ((i=0; i<4; ++i)); do 
    for ((j=0; j<5; ++j)); do 
    a[i*5+j]=0 
    done 
done 

那么你a[2][3] = 3变得

a[2*5+3] = 3 

这种方法可能是值得变成了一组函数,但因为你不能传递数组或返回数组功能,你将不得不使用通过名称,有时eval。所以我倾向于在“事情根本就不是想做”的情况下提交多维数组。

0

为了模拟一个2维阵列,我首先加载第一n元件(第一列中的元素)

local pano_array=() 

i=0 

for line in $(grep "filename" "$file") 
do 
    url=$(extract_url_from_xml $line) 
    pano_array[i]="$url" 
    i=$((i+1)) 
done 

要添加第二列中,我限定第一列的大小和计算中的值的偏移可变

array_len="${#pano_array[@]}" 

i=0 

while [[ $i -lt $array_len ]] 
do 
    url="${pano_array[$i]}" 
    offset=$(($array_len+i)) 
    found_file=$(get_file $url) 
    pano_array[$offset]=$found_file 

    i=$((i+1)) 
done