9 ответов:
вы можете имитировать их, например, с хэшами, но нужно заботиться о ведущих нулях и многих других вещах. Следующая демонстрация работает, но это далеко не оптимальное решение.
#!/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приведенный выше пример создает матрицу 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принцип: создание одного ассоциативного массива, где индекс является строкой типа
3,4. Преимущества:
- вполне возможно использовать для массивов любого размера;) например:
30,40,2для 3-х мерных.- синтаксис близок к" C", как массивы
${matrix[2,3]}
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_fileEdit 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
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(значение справа от оператора запятой).
вы также можете подойти к этому гораздо менее умным способом
q=() q+=( 1-2 ) q+=( a-b ) for set in ${q[@]}; do echo ${set%%-*} echo ${set##*-} doneконечно, 22-строчное решение или косвенность, вероятно, лучший способ пойти и почему бы не посыпать eval каждый, где нужно .
способ моделирования массивов в bash (он может быть адаптирован для любого числа измерений массива):
#!/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 in the next element position (vector length + 1) in vector local elem_value local vector_length local elem_name eval elem_value=\"$\" eval vector_length=$\_0 if [ -z "$vector_length" ]; then vector_length=$((0)) fi vector_length=$(( vector_length + 1 )) elem_name=_$vector_length eval $elem_name=\"$elem_value\" eval _0=$vector_length } VectorAddElementDVNext () { # Vector Add Element Direct Value Next # Adds the string in the next element position (vector length + 1) in vector local elem_value local vector_length local elem_name eval elem_value="" eval vector_length=$\_0 if [ -z "$vector_length" ]; then vector_length=$((0)) fi vector_length=$(( vector_length + 1 )) elem_name=_$vector_length eval $elem_name=\"$elem_value\" eval _0=$vector_length } VectorAddElement () { # Vector Add Element # Adds the string contained in the variable in the position contained in (variable or direct value) in the vector local elem_value local elem_position local vector_length local elem_name eval elem_value=\"$\" elem_position=$(()) eval vector_length=$\_0 if [ -z "$vector_length" ]; then vector_length=$((0)) fi if [ $elem_position -ge $vector_length ]; then vector_length=$elem_position fi elem_name=_$elem_position eval $elem_name=\"$elem_value\" if [ ! $elem_position -eq 0 ]; then eval _0=$vector_length fi } VectorAddElementDV () { # Vector Add Element # Adds the string in the position (variable or direct value) in the vector local elem_value local elem_position local vector_length local elem_name eval elem_value="" elem_position=$(()) eval vector_length=$\_0 if [ -z "$vector_length" ]; then vector_length=$((0)) fi if [ $elem_position -ge $vector_length ]; then vector_length=$elem_position fi elem_name=_$elem_position eval $elem_name=\"$elem_value\" if [ ! $elem_position -eq 0 ]; then eval _0=$vector_length fi } VectorPrint () { # Vector Print # Prints all the elements names and values of the vector on sepparate lines local vector_length vector_length=$((_0)) if [ "$vector_length" = "0" ]; then echo "Vector \"\" is empty!" else echo "Vector \"\":" for ((i=1; i<=$vector_length; i++)); do eval echo \"[$i]: \\"$\_$i\\"\" ###OR: eval printf \'\%s\\n\' \"[$i]: \\"$\_$i\\"\" done fi } VectorDestroy () { # Vector Destroy # Empties all the elements values of the vector local vector_length vector_length=$((_0)) if [ ! "$vector_length" = "0" ]; then for ((i=1; i<=$vector_length; i++)); do unset _$i done unset _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 ### ################
# 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[]}" tmp[]= a[]="${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
можно просто определить две функции для записи ($4-назначенное значение) и прочитать матрицу с произвольным именем ($1) и индексами ($2 и $ 3), используя eval и косвенную ссылку.
#!/bin/bash matrix_write () { eval "_""_"= # aux="_""_" # Alternative way # let $aux= # --- } matrix_read () { aux="_""_" 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
если каждая строка матрицы имеет одинаковый размер, то вы можете просто использовать линейный массив и умножение.
то есть
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этот подход может быть стоит превратить в набор функций, но так как вы не можете передавать массивы или возвращать массивы из функций, вам придется использовать pass-by-name и иногда
eval. Поэтому я склонен подавать многомерные массивы в разделе " вещи bash просто не предназначены Делать."
для моделирования 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добавить второй столбец, я определяю размер первого столбца и вычислить значения переменной offset
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
Comments