Übrigens ist ein mehrdimensionales Array tatsächlich (tief im Inneren) ein eindimensionales Array, das etwas anders gehandhabt wird, insbesondere wenn es um den Zugriff auf seine Elemente geht. Zum Beispiel hat eine 3x4-Matrix 12 Zellen. Die "Zeilen", die Sie mit einer äußeren Schleife mit einem Schritt von 3 durchlaufen, und die "Spalten", die Sie mit einer inneren Schleife mit einem Schritt von 1
durchlaufen.
Antworten:
70
Sie können sie beispielsweise mit Hashes simulieren, müssen sich jedoch um die führenden Nullen und viele andere Dinge kümmern. Die nächste Demonstration funktioniert, ist aber alles andere als eine optimale Lösung.
#!/bin/bashdeclare -A matrix
num_rows=4
num_columns=5
for ((i=1;i<=num_rows;i++)) dofor ((j=1;j<=num_columns;j++)) do
matrix[$i,$j]=$RANDOMdonedone
f1="%$((${#num_rows}+1))s"
f2=" %9s"printf"$f1"''for ((i=1;i<=num_rows;i++)) doprintf"$f2"$idoneechofor ((j=1;j<=num_columns;j++)) doprintf"$f1"$jfor ((i=1;i<=num_rows;i++)) doprintf"$f2"${matrix[$i,$j]}doneechodone
Im obigen Beispiel wird eine 4x5-Matrix mit Zufallszahlen erstellt und mit dem Beispielergebnis transponiert gedruckt
Der offensichtliche Nachteil dieses Verfahrens besteht darin, dass die Länge einer Dimension nicht bekannt ist. Trotzdem funktioniert es in den meisten anderen Szenarien hervorragend! Vielen Dank!!
Bhavin Doshi
Können Sie bitte erklären, was f1und f2was?
CL22
1
@Jodes the f1und f2enthält das formatfür das printffür den schön ausgerichteten Drucken. Es könnte zum Beispiel fest codiert sein, printf "%2s"aber die Verwendung von Variablen ist flexibler - wie oben f1. Der widthvon der Zeilennummer wird als die Länge der berechneten $num_rowsVariable - zB wenn die Anzahl der Zeilen $num_rows9 ist, seine Länge ist 1das Format wird 1+1so %2s. Für den $num_rows2500 ist seine Länge 4so, dass das Format sein wird %5s- und so weiter ...
jm666
24
Bash unterstützt keine mehrdimensionalen Arrays.
Sie können es jedoch mithilfe der indirekten Erweiterung simulieren:
#!/bin/bashdeclare -a a0=(1 2 3 4)
declare -a a1=(5 6 7 8)
var="a1[1]"echo${!var}# outputs 6
Zuweisungen sind auch mit dieser Methode möglich:
let$var=55
echo${a1[1]}# outputs 55
Bearbeiten 1 : Verwenden Sie Folgendes, um ein solches Array aus einer Datei mit jeder Zeile in einer Zeile und durch Leerzeichen getrennten Werten zu lesen:
idx=0
whileread -a a$idx; dolet idx++;
done </tmp/some_file
Bearbeiten 2 : Zum Deklarieren und Initialisieren a0..a3[0..4]von 0können Sie Folgendes ausführen:
for i in {0..3}; doeval"declare -a a$i=( $(for j in {0..4}; do echo 0; done) )"done
Können Sie bitte zeigen, wie die obige "2d-Array-Simulation" aus einer Dateitabelle gefüllt wird? zB eine Datei mit einer zufälligen Anzahl von Zeilen und in jeder Zeile mit 5 durch Leerzeichen getrennten Zahlen.
Kobame
@kobame: Ich habe die Antwort bearbeitet, um eine Lösung für Ihre Fragen bereitzustellen. Es wird ein 2d-Array mit einer variablen Anzahl von Zeilen und einer variablen Anzahl von Spalten in a0, a1 usw. gelesen.
Sir Athos
Wie würden Sie ein anderes Trennzeichen wie ein Komma oder einen Tabulator verwenden?
MountainX
23
Bash hat kein mehrdimensionales Array. Mit assoziativen Arrays können Sie jedoch einen ähnlichen Effekt simulieren. Das Folgende ist ein Beispiel für ein assoziatives Array, das vorgibt, als mehrdimensionales Array verwendet zu werden:
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
Wenn Sie das Array nicht als assoziativ (mit -A) deklarieren , funktioniert das oben Gesagte nicht. Wenn Sie beispielsweise die declare -A arrZeile weglassen , echowird 2 3anstelle von 0 1, weil gedruckt 0,0, 1,0und dies wird als arithmetischer Ausdruck verwendet und als 0(der Wert rechts vom Kommaoperator) ausgewertet .
Wo verwendet die 22-Zeilen-Lösung die Indirektion? Was werden Sie für Ihre Lösung tun, wenn Sie ein Skript schreiben, für das E / A erforderlich ist und ein Benutzer ein -in das 'Array' eingeben möchte ? Auch wenn Sie ein Array simulieren möchten, ist dies wahrscheinlich sinnvoller als echo ${set//-/ }Ihre beiden.
Setzen Sie Monica bitte
Das war mein Fehler, den ich verpasst habe. Ich denke, dass $ {set // - /} wahrscheinlich ein besserer Weg ist (ich weiß nichts über die Portabilitätsprobleme von %% und ##, obwohl ich Ihnen glaube). Was ist, wenn es eine sehr gefährliche Frage ist? Wenn Sie sie zu oft stellen, werden Sie feststellen, dass Sie KI für Ihren Optionsparser benötigen: {p
Ich verstehe nicht, wie das relevant ist oder hilft, die Frage zu beantworten. $ {set // - /} würde das '-' entfernen und die Werte zusammenführen. Das heißt, das Echo führt zu 'ab', während der ursprüngliche Code entweder 'a' oder 'b' zurückgibt, je nachdem, welche Seite des '-' Sie möchten.
MrPotatoHead
5
Ein anderer Ansatz besteht darin, dass Sie jede Zeile als Zeichenfolge darstellen können, dh das 2D-Array einem 1D-Array zuordnen. Dann müssen Sie nur noch die Zeichenfolge der Zeile entpacken und neu packen, wenn Sie eine Bearbeitung vornehmen:
# Init a 4x5 matrix
a=("00 01 02 03 04""10 11 12 13 14""20 21 22 23 24""30 31 32 33 34")
aset() {
row=$1
col=$2
value=$3
IFS=' 'read -r -a tmp <<< "${a[$row]}"
tmp[$col]=$value
a[$row]="${tmp[@]}"
}
# Set a[2][3] = 9999
aset 2 3 9999
# Show resultfor r in"${a[@]}"; doecho$rdone
Eine Möglichkeit, Arrays in Bash zu simulieren (kann für eine beliebige Anzahl von Dimensionen eines Arrays angepasst werden):
#!/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 elementsVectorAddElementNext () {
# Vector Add Element Next# Adds the string contained in variable $2 in the next element position (vector length + 1) in vector $1local 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_lengtheval$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 $1local 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_lengtheval$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 $1local 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))
fiif [ $elem_position -ge $vector_length ]; then
vector_length=$elem_positionfi
elem_name=$1_$elem_positioneval$elem_name=\"\$elem_value\"
if [ ! $elem_position -eq 0 ]; theneval$1_0=$vector_lengthfi
}
VectorAddElementDV () {
# Vector Add Element# Adds the string $3 in the position $2 (variable or direct value) in the vector $1local 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))
fiif [ $elem_position -ge $vector_length ]; then
vector_length=$elem_positionfi
elem_name=$1_$elem_positioneval$elem_name=\"\$elem_value\"
if [ ! $elem_position -eq 0 ]; theneval$1_0=$vector_lengthfi
}
VectorPrint () {
# Vector Print# Prints all the elements names and values of the vector $1 on sepparate lineslocal vector_length
vector_length=$(($1_0))
if [ "$vector_length" = "0" ]; thenecho"Vector \"$1\" is empty!"elseecho"Vector \"$1\":"for ((i=1; i<=$vector_length; i++)); doevalecho \"[$i]: \\\"\$$1\_$i\\\"\"
###OR: eval printf \'\%s\\\n\' \"[\$i]: \\\"\$$1\_$i\\\"\"donefi
}
VectorDestroy () {
# Vector Destroy# Empties all the elements values of the vector $1local vector_length
vector_length=$(($1_0))
if [ ! "$vector_length" = "0" ]; thenfor ((i=1; i<=$vector_length; i++)); dounset$1_$idoneunset$1_0fi
}
##################### MAIN START ####################### Setting vector 'params' with all the parameters received by the script:for ((i=1; i<=$#; i++)); doeval 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" ]; thenfor ((i=1; i<=$params_0; i++)); do
count=$((params_0-i+1))
VectorAddElement params2 count params_$idonefi# Printing the vector 'params2':
VectorPrint params2
read temp
## Getting the values of 'params2'`s elements and printing them:if [ -n "$params2_0" ]; thenecho"Printing the elements of the vector 'params2':"for ((i=1; i<=$params2_0; i++)); doeval current_elem_value=\"\$params2\_$i\"
echo"params2_$i=\"$current_elem_value\""doneelseecho"Vector 'params2' is empty!"firead 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$valuedonedone## Manually printing the two dimensional array ('a'):echo"Printing the two-dimensional array 'a':"if [ -n "$a_0" ]; thenfor ((i=1; i<=$a_0; i++)); doeval current_vector_lenght=\$a\_$i\_0
if [ -n "$current_vector_lenght" ]; thenfor ((j=1; j<=$current_vector_lenght; j++)); doeval value=\"\$a\_$i\_$j\"
printf"$value "donefiprintf"\n"donefi################### MAIN END ###################
Wenn jede Zeile der Matrix dieselbe Größe hat, können Sie einfach ein lineares Array und eine Multiplikation verwenden.
Das ist,
a=()
for (( i=0; i<4; ++i )); dofor (( j=0; j<5; ++j )); do
a[i*5+j]=0
donedone
Dann a[2][3] = 3wird
a[2*5+3] = 3
Es könnte sich lohnen, diesen Ansatz in eine Reihe von Funktionen umzuwandeln. Da Sie jedoch keine Arrays an Funktionen übergeben oder von diesen zurückgeben können, müssen Sie manchmal die Namensübergabe verwenden eval. Daher neige ich dazu, mehrdimensionale Arrays unter "Dinge, die Bash einfach nicht zu tun hat" abzulegen.
Man kann einfach zwei Funktionen definieren, die geschrieben werden sollen ($ 4 ist der zugewiesene Wert) und eine Matrix mit einem beliebigen Namen ($ 1) und Indizes ($ 2 und $ 3) lesen, wobei eval und indirekte Referenzierung ausgenutzt werden.
#!/bin/bashmatrix_write () {
eval$1"_"$2"_"$3=$4# aux=$1"_"$2"_"$3 # Alternative way# let $aux=$4 # ---
}
matrix_read () {
aux=$1"_"$2"_"$3echo${!aux}
}
for ((i=1;i<10;i=i+1)); dofor ((j=1;j<10;j=j+1)); do
matrix_write a $i$j $[$i*10+$j]
donedonefor ((i=1;i<10;i=i+1)); dofor ((j=1;j<10;j=j+1)); doecho"a_"$i"_"$j"="$(matrix_read a $i$j)
donedone
Hallo, fügen Sie zusammen mit dem Code eine Erklärung hinzu, da dies zum Verständnis Ihres Codes beiträgt. Nur Code-Antworten sind verpönt.
Bhargav Rao
1
2D-Array kann in Bash erreicht werden, indem 1D-Array deklariert wird, und dann kann mit auf Elemente zugegriffen werden (r * col_size) + c). Die folgende Logik löscht 1D-Array ( str_2d_arr) und druckt als 2D-Array.
Der folgende Code funktioniert auf jeden Fall, vorausgesetzt, Sie arbeiten auf einem Mac mit Bash-Version 4. Sie können nicht nur 0 deklarieren, sondern dies ist eher ein universeller Ansatz zum dynamischen Akzeptieren von Werten.
2D-Array
declare -A arr
echo"Enter the row"read r
echo"Enter the column"read c
i=0
j=0
echo"Enter the elements"while [ $i -lt $r ]
do
j=0
while [ $j -lt $c ]
doecho$i$jread m
arr[${i},${j}]=$m
j=`expr $j + 1`
done
i=`expr $i + 1`
done
i=0
j=0
while [ $i -lt $r ]
do
j=0
while [ $j -lt $c ]
doecho -n ${arr[${i},${j}]} " "
j=`expr $j + 1`
doneecho""
i=`expr $i + 1`
done
Mark Reed schlug eine sehr gute Lösung für 2D-Arrays (Matrix) vor! Sie können immer in ein 1D-Array (Vektor) konvertiert werden. Obwohl Bash keine native Unterstützung für 2D-Arrays bietet, ist es nicht so schwierig, eine einfache ADT nach dem genannten Prinzip zu erstellen.
Antworten:
Sie können sie beispielsweise mit Hashes simulieren, müssen sich jedoch um die führenden Nullen und viele andere Dinge kümmern. Die nächste Demonstration funktioniert, ist aber alles andere als eine optimale Lösung.
#!/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
Im obigen Beispiel wird eine 4x5-Matrix mit Zufallszahlen erstellt und mit dem Beispielergebnis transponiert gedruckt
Das Prinzip lautet: Erstellen eines assoziativen Arrays, bei dem der Index einer Zeichenfolge ähnelt
3,4
. Die Vorteile:30,40,2
für 3-dimensionale.${matrix[2,3]}
quelle
f1
undf2
was?f1
undf2
enthält dasformat
für dasprintf
für den schön ausgerichteten Drucken. Es könnte zum Beispiel fest codiert sein,printf "%2s"
aber die Verwendung von Variablen ist flexibler - wie obenf1
. Derwidth
von der Zeilennummer wird als die Länge der berechneten$num_rows
Variable - zB wenn die Anzahl der Zeilen$num_rows
9 ist, seine Länge ist1
das Format wird1+1
so%2s
. Für den$num_rows
2500 ist seine Länge4
so, dass das Format sein wird%5s
- und so weiter ...Bash unterstützt keine mehrdimensionalen Arrays.
Sie können es jedoch mithilfe der indirekten Erweiterung simulieren:
#!/bin/bash declare -a a0=(1 2 3 4) declare -a a1=(5 6 7 8) var="a1[1]" echo ${!var} # outputs 6
Zuweisungen sind auch mit dieser Methode möglich:
let $var=55 echo ${a1[1]} # outputs 55
Bearbeiten 1 : Verwenden Sie Folgendes, um ein solches Array aus einer Datei mit jeder Zeile in einer Zeile und durch Leerzeichen getrennten Werten zu lesen:
idx=0 while read -a a$idx; do let idx++; done </tmp/some_file
Bearbeiten 2 : Zum Deklarieren und Initialisieren
a0..a3[0..4]
von0
können Sie Folgendes ausführen:for i in {0..3}; do eval "declare -a a$i=( $(for j in {0..4}; do echo 0; done) )" done
quelle
Bash hat kein mehrdimensionales Array. Mit assoziativen Arrays können Sie jedoch einen ähnlichen Effekt simulieren. Das Folgende ist ein Beispiel für ein assoziatives Array, das vorgibt, als mehrdimensionales Array verwendet zu werden:
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
Wenn Sie das Array nicht als assoziativ (mit
-A
) deklarieren , funktioniert das oben Gesagte nicht. Wenn Sie beispielsweise diedeclare -A arr
Zeile weglassen ,echo
wird2 3
anstelle von0 1
, weil gedruckt0,0
,1,0
und dies wird als arithmetischer Ausdruck verwendet und als0
(der Wert rechts vom Kommaoperator) ausgewertet .quelle
Sie können dies auch viel weniger intelligent angehen
q=() q+=( 1-2 ) q+=( a-b ) for set in ${q[@]}; do echo ${set%%-*} echo ${set##*-} done
Natürlich ist eine 22-Zeilen-Lösung oder Indirektion wahrscheinlich der bessere Weg, und warum nicht überall eval streuen.
quelle
-
in das 'Array' eingeben möchte ? Auch wenn Sie ein Array simulieren möchten, ist dies wahrscheinlich sinnvoller alsecho ${set//-/ }
Ihre beiden.Ein anderer Ansatz besteht darin, dass Sie jede Zeile als Zeichenfolge darstellen können, dh das 2D-Array einem 1D-Array zuordnen. Dann müssen Sie nur noch die Zeichenfolge der Zeile entpacken und neu packen, wenn Sie eine Bearbeitung vornehmen:
# Init a 4x5 matrix a=("00 01 02 03 04" "10 11 12 13 14" "20 21 22 23 24" "30 31 32 33 34") aset() { row=$1 col=$2 value=$3 IFS=' ' read -r -a tmp <<< "${a[$row]}" tmp[$col]=$value a[$row]="${tmp[@]}" } # Set a[2][3] = 9999 aset 2 3 9999 # Show result for r in "${a[@]}"; do echo $r done
Ausgänge:
quelle
Eine Möglichkeit, Arrays in Bash zu simulieren (kann für eine beliebige Anzahl von Dimensionen eines Arrays angepasst werden):
#!/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 ### ################
quelle
Wenn jede Zeile der Matrix dieselbe Größe hat, können Sie einfach ein lineares Array und eine Multiplikation verwenden.
Das ist,
a=() for (( i=0; i<4; ++i )); do for (( j=0; j<5; ++j )); do a[i*5+j]=0 done done
Dann
a[2][3] = 3
wirdEs könnte sich lohnen, diesen Ansatz in eine Reihe von Funktionen umzuwandeln. Da Sie jedoch keine Arrays an Funktionen übergeben oder von diesen zurückgeben können, müssen Sie manchmal die Namensübergabe verwenden
eval
. Daher neige ich dazu, mehrdimensionale Arrays unter "Dinge, die Bash einfach nicht zu tun hat" abzulegen.quelle
Man kann einfach zwei Funktionen definieren, die geschrieben werden sollen ($ 4 ist der zugewiesene Wert) und eine Matrix mit einem beliebigen Namen ($ 1) und Indizes ($ 2 und $ 3) lesen, wobei eval und indirekte Referenzierung ausgenutzt werden.
#!/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
quelle
2D-Array kann in Bash erreicht werden, indem 1D-Array deklariert wird, und dann kann mit auf Elemente zugegriffen werden
(r * col_size) + c)
. Die folgende Logik löscht 1D-Array (str_2d_arr
) und druckt als 2D-Array.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 ""
Ausgabe ist
Die folgende Logik ist sehr nützlich, um jede Zeile aus dem oben deklarierten 1D-Array abzurufen
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 ""
Ausgabe ist
quelle
Um ein zweidimensionales Array zu simulieren, lade ich zuerst die ersten n-Elemente (die Elemente der ersten Spalte).
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
Um die zweite Spalte hinzuzufügen, definiere ich die Größe der ersten Spalte und berechne die Werte in einer Versatzvariablen
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
quelle
Der folgende Code funktioniert auf jeden Fall, vorausgesetzt, Sie arbeiten auf einem Mac mit Bash-Version 4. Sie können nicht nur 0 deklarieren, sondern dies ist eher ein universeller Ansatz zum dynamischen Akzeptieren von Werten.
2D-Array
declare -A arr echo "Enter the row" read r echo "Enter the column" read c i=0 j=0 echo "Enter the elements" while [ $i -lt $r ] do j=0 while [ $j -lt $c ] do echo $i $j read m arr[${i},${j}]=$m j=`expr $j + 1` done i=`expr $i + 1` done i=0 j=0 while [ $i -lt $r ] do j=0 while [ $j -lt $c ] do echo -n ${arr[${i},${j}]} " " j=`expr $j + 1` done echo "" i=`expr $i + 1` done
quelle
Mark Reed schlug eine sehr gute Lösung für 2D-Arrays (Matrix) vor! Sie können immer in ein 1D-Array (Vektor) konvertiert werden. Obwohl Bash keine native Unterstützung für 2D-Arrays bietet, ist es nicht so schwierig, eine einfache ADT nach dem genannten Prinzip zu erstellen.
Hier ist ein Barebone-Beispiel ohne Argumentprüfungen usw., um die Lösung klar zu halten: Die Größe des Arrays wird als zwei erste Elemente in der Instanz festgelegt (Dokumentation für das Bash-Modul, das eine Matrix-ADT implementiert, https://github.com) /vorakl/bash-libs/blob/master/src.docs/content/pages/matrix.rst )
#!/bin/bash matrix_init() { # matrix_init instance x y data ... declare -n self=$1 declare -i width=$2 height=$3 shift 3; self=(${width} ${height} "$@") } matrix_get() { # matrix_get instance x y declare -n self=$1 declare -i x=$2 y=$3 declare -i width=${self[0]} height=${self[1]} echo "${self[2+y*width+x]}" } matrix_set() { # matrix_set instance x y data declare -n self=$1 declare -i x=$2 y=$3 declare data="$4" declare -i width=${self[0]} height=${self[1]} self[2+y*width+x]="${data}" } matrix_destroy() { # matrix_destroy instance declare -n self=$1 unset self } # my_matrix[3][2]=( (one, two, three), ("1 1" "2 2" "3 3") ) matrix_init my_matrix \ 3 2 \ one two three \ "1 1" "2 2" "3 3" # print my_matrix[2][0] matrix_get my_matrix 2 0 # print my_matrix[1][1] matrix_get my_matrix 1 1 # my_matrix[1][1]="4 4 4" matrix_set my_matrix 1 1 "4 4 4" # print my_matrix[1][1] matrix_get my_matrix 1 1 # remove my_matrix matrix_destroy my_matrix
quelle