2013-05-10 183 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