## declare an array variable
declare -a arr=("element 1" "element 2" "element 3")
## loop through above array (quotes are important if your elements may contain spaces)
for i in "${arr[@]}"
do
echo "$i"
# or do whatever with individual element of array
done
# You can access them using echo "${arr[0]}", "${arr[1]}" also
Also works for multi-line array declaration
declare -a arr=("element1"
"element2" "element3"
"element4"
)
Answer from anubhava on Stack Overflow## declare an array variable
declare -a arr=("element 1" "element 2" "element 3")
## loop through above array (quotes are important if your elements may contain spaces)
for i in "${arr[@]}"
do
echo "$i"
# or do whatever with individual element of array
done
# You can access them using echo "${arr[0]}", "${arr[1]}" also
Also works for multi-line array declaration
declare -a arr=("element1"
"element2" "element3"
"element4"
)
for databaseName in a b c d e f; do
# do something like: echo $databaseName
done
See Bash Loops for, while and until for details.
bash - How do I select an array to loop through from an array of arrays? - Unix & Linux Stack Exchange
bash - In a loop over an array, add an element to the array - Unix & Linux Stack Exchange
shell script - Using a for loop to loop over multiple arrays in bash - Unix & Linux Stack Exchange
shell script - Bash - Looping through nested for loop using arrays - Unix & Linux Stack Exchange
How do I loop over command-line arguments?
What is the difference between the standard `for` loop and the C-style `for` loop?
How do I loop over lines in a file?
Videos
The principle error is that for i in $arrayVM sets i to the first element in arrayVM, since there is no index. I am surprised that this does not give an error on the echo command, unless the first array element is numeric.
What you need is the iterative form of for:-
for (( i=0; i<${#arrayVM[*]}; ++i ))
do
echo ${arrayVM[$i]}>>list
done
However, this is unnecessarily long-winded: much simpler is:-
for e in "${arrayVM[@]}"
do
echo $e>>list
done
This assigns e to each element in turn, without enumerating them.
In the light of Fedorqui's answer, if arrayVM is not needed elsewhere, then there is a much simpler way to create the list file:-
cat /orch/servers | grep $1 | awk '{print $1}' >/orch/list
Or, since the cat is unnecessary:-
grep $1 </orch/servers | awk '{print $1}' >/orch/list
If you don't need the data to be stored in an array but you also want to use every record for other things, you can loop normally through the data with a process substitution:
while IFS= read -r value _;
do
echo "$value" >> list
done < <(grep "$1" /orch/servers)
With read -r value _ we are storing the first field in $value and the rest in the throw away variable $_.
You'll store the array names in aoarrs, and inside the select body declare a nameref to the chosen name:
ARGENT=("Nous devons économiser de l'argent."
"Je dois économiser de l'argent.")
BIENETRE=("Comment vas-tu?" "Tout va bien ?")
aoarrs=(ARGENT BIENETRE)
PS3='Which array? '
select arr in "${aoarrs[@]}"; do
[[ $arr ]] || continue
declare -n ref=$arr
for i in "${!ref[@]}"; do
printf '%d\t%s\n' $i "${ref[i]}"
done
break
done
Running might look like
1) ARGENT
2) BIENETRE
Which array? 3
Which array? 4
Which array? 5
Which array? 2
0 Comment vas-tu?
1 Tout va bien ?
You'd want a mapping of "keys" to "values", where "values" are the lists of strings, and the "keys" are ARGENT, BIENETRE…
You're on the right path with aoarrs, because you could use that array as associative array:
declare -A aoarrs
aoarrs[ARGENT]=$ARGENT
aoarrs[BIENETRE]=$BIENETRE
and then just iterate over all keys in that array using something like for key in ${!aoarrs[@]}….
Sadly, bash doesn't, for whatever reason, allow lists to be elements of these associative arrays.
So, things suck. You can for example join the elements of your lists with a reserved character to split them later on (that's stupid because it means you can't have all characters in your string, or need to start escaping them), or you build your own functions that take lists of strings, append them to a large array and then you implement your own associative lookup function on that container (that would be stupid; not only would it be slow, it would also require you to write relatively much code in a relatively ill-suited language). It would look terrible. Here's an example which I write down without testing it, because it's ugly enough that I need to get it out of my head, but don't want to deal with it any further:
#!/bin/bash
###############################
# UNTESTED STUFF #
# If you think this code is #
# acceptable, consider doing #
# something good for yourself #
# once in a while #
###############################
declare -A index
declare -A lengths
declare -a storage
# Adds an entry to our our custom container
#
# Usage:
# add_key_values KEY "list element 1" "list element 2" …
function add_key_values() {
local key="$1"
shift
local -n valuelist=$@
# get the length of the passed list, to save it
local lengthlist=${#valuelist[@]}
# get the end of the current storage, that's where we start adding
# our list
local start_index=${#storage[@]}
# finally, actually store the list items in the storage
for item in "${valuelist[@]}"; do
storage+=("${item}")
done
lengths["${key}"]=$lengthlist
index["${key}"]=$start_index
}
# Retrieve a list from the storage
# Sadly, bash is not a proper programming language, because what it calls
# "functions" don't do the one thing that a function needs to do:
# return a value for an argument. There's just no "return" mechanism in bash.
#
# Returns an empty list if the key wasn't found.
#
# So, after sobbing a bit, we just say
# Usage:
# get_values $key
# Overwrites the `ret_val` variable with the list that was saved earlier
function get_values() {
# prepare ret_val
declare -g -a ret_val=()
local key=$1
# We return (with ret_val empty) if key isn't present
# frigging bash doesn't have a "is key present in associative array" function…
# so this is the workaround to check whether there's $key in $index.
# seriously.
local teststring
teststring="$(printf 'index[%s]' "${key}")"
# you need quite modern bash to even get the "is defined" -v test
[[ -v "${teststring}" ]] || return
# let's get all the elements from storage and append them to ret_val
local start=${index[$key]}
local length=${lengths[$key]}
for idx in $(seq $(( start - 1 )) $((start - 1 + length)) ); do
ret_val+=("${storage[idx]}")
done
}
####################
# EXAMPLE USAGE
####################
add_key_values "ARGENT" "Nous devons économiser de l'argent." "Je dois économiser de l'argent."
add_key_values "BIENETRE" ("Comment vas-tu?" "Tout va bien ?")
for key in ${!index[@]}; do
echo "the list for value $key contains"
get_values "${key}"
for element in ${ret_val[@]}; do
echo "element: ${element}"
done
done
The next option is magic that involves "indirect addressing" of variables by name using eval. That's kind of evil, and stupid, and there's very many posts on here that hint at "if you're at that point, then maybe use a proper programming language instead of bash".
I'd concur with that: This whole problem would literally be done in four lines of python, with the first two lines would be storing "ARGENT" and "BIENETRE" and their lists into a dict. Or really, in any other common language that's not bash (or C, for that matter), associative arrays are less bad.
It will append "sbin" 3 times as it should, but it won't iterate over the newly added "sbin"s in the same loop.
After the 2nd example:
echo "${array[@]}"
#=> etc bin var sbin sbin sbin
set etc bin var
while [ "$#" -gt 1 ]
do [ "$1" = bin ] &&
set "$@" sbin
printf %s\\n "$1"
shift;done
That will iterate over your list, tack sbin onto the end of said list conditionally, and include sbin in the iterable content.
You're iterating over the wrong thing. Your for saves each element of the array as $i, not the array's indices. What you want is something like
#!/usr/bin/env bash
a0=(1 2 3 4)
a1=(5 6 7 8)
for ((i=0;i<${#a0[@]};i++))
do
echo ${a0[$i]} ${a1[$i]};
done
As you’ve presumably learned by now from your research, bash doesn’t support multi-dimensional arrays per se, but it does support “associative” arrays. These are basically indexed by a string, rather than a number, so you can have, for example,
grade[John]=100
grade[Paul]=100
grade[George]=90
grade[Ringo]=80
As demonstrated (but not explained very well) in the accepted answer of the question you linked to, indices of associative arrays can contain commas, and so a common trick is to concatenate your individual indices (0-1 × 0-3) into a string, separated by commas. While this is more cumbersome than ordinary arrays, it can be effective:
$ declare -A a <-- Create the associative array.
$ a[0,0]=1
$ a[0,1]=2
$ a[0,2]=3
$ a[0,3]=4
$ a[1,0]=5
$ a[1,1]=6
$ a[1,2]=7
$ a[1,3]=8
$ for i in 0 1
> do
> echo ${a[$i,2]}
> done
3 <-- And here’s your output.
7 To expand array indirection, the string [@] must be part of the variable. It works for the values:
for thelist in "${master_list[@]}" ; do
reallist=$thelist[@]
for key in "${!reallist}" ; do
echo "the key is: $key"
done
done
For the keys, I don't see a way without eval.
for thelist in "${master_list[@]}" ; do
eval keys=('"${!'$thelist'[@]}"')
for key in "${keys[@]}" ; do
echo "the key is: $key"
done
done
As far as you're sure the master_list contains only variable names, it should be safe.
It's fun to play with bash, but bash seems to have some issues to follow your imagination ;)
list_a=( 1 2 )
list_b=( 3 4 )
for key in "${list_a[@]}" "${list_b[@]}"; do
echo "the key is: $key"
done
Output :
the key is: 1
the key is: 2
the key is: 3
the key is: 4