Loop through an array of strings in Bash?

Loop through an array of strings in Bash?



I want to write a script that loops through 15 strings (array possibly?) Is that possible?



Something like:


for databaseName in listOfNames
then
# Do something
end




18 Answers
18



You can use it like this:


## declare an array variable
declare -a arr=("element1" "element2" "element3")

## now loop through the above array
for i in "$arr[@]"
do
echo "$i"
# or do whatever with individual element of the 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"
)





somehow the "" around $i is required to access each array element, can you explain why or point to some material I can read to understand it? Thanks so much!
– olala
Sep 26 '14 at 16:22






In BASH it is safer to quote the variable using "" for the cases when $i may contain white spaces or shell expandable characters.
– anubhava
Sep 26 '14 at 16:29


""


$i





It does work with spaces in elements if it is quoted like showed above. Better you test it yourself.
– anubhava
Nov 12 '14 at 10:19





What are the advantages of declare -a? Can't I do something simpler, like arr=("element1" "element2" "element3")?
– Ignorant
Jan 19 '16 at 14:15



declare -a


arr=("element1" "element2" "element3")





declare or typeset are an explicit way of declaring variable in shell scripts.
– anubhava
Jan 19 '16 at 15:38


declare


typeset



That is possible, of course.


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.





What is the problem with this approach? In simple cases it seems to work and, then, is more intuitive than @anubhava's answer.
– Jan-Philip Gehrcke
Aug 30 '12 at 11:54





This works particularly well with command substitution, eg for year in $(seq 2000 2013).
– Brad Koch
May 20 '13 at 14:53


for year in $(seq 2000 2013)





The problem is that he asked about iterating through an array.
– mgalgs
Jul 18 '13 at 23:00





The 'declare' approach works best if you have to iterate over the same array in more than one place. This approach is cleaner but less flexible.
– StampyCode
Jan 3 '14 at 10:21





Why isn't this #1? It's cleaner, and you can easily reuse the array just by setting a string, i.e., DATABASES="a b c d e f".
– Nerdmaster
Jul 2 '14 at 21:42


DATABASES="a b c d e f"



None of those answers include a counter...


#!/bin/bash
## declare an array variable
declare -a array=("one" "two" "three")

# get length of an array
arraylength=$#array[@]

# use for loop to read all values and indexes
for (( i=1; i<$arraylength+1; i++ ));
do
echo $i " / " $arraylength " : " $array[$i-1]
done



Output:


1 / 3 : one
2 / 3 : two
3 / 3 : three





This should be the accepted answer, is the only one that works when array elements contain spaces.
– jesjimher
Nov 12 '14 at 9:40





You should start i at 0 for sanity, of course.
– GManNickG
Feb 3 '15 at 19:32





That's just for the sake of the example's output with a counter. It's also quite trivial to change that, and works just the same.
– caktux
Jul 9 '15 at 5:35





The echo at the end is buggy. You don't need to quote constants, you need to quote expansions, or can safely just quote both as follows: echo "$i / $arraylength : $array[$i-1]" -- otherwise, if your $i contains a glob it'll be expanded, if it contains a tab it'll be changed to a space, etc.
– Charles Duffy
Jul 9 '16 at 15:02



echo "$i / $arraylength : $array[$i-1]"


$i





@bzeaman, sure -- but if you're sloppy about such things then it requires contextual analysis (as you just did) to prove something correct, and re-analysis if that context changes or the code is reused in a different place or for whatever other reason an unexpected control flow is possible. Write it the robust way and it's correct regardless of context.
– Charles Duffy
Sep 2 '16 at 14:57




In the same spirit as 4ndrew's answer:


listOfNames="RA
RB
R C
RD"

# To allow for other whitespace in the string:
# 1. add double quotes around the list variable, or
# 2. see the IFS note (under 'Side Notes')

for databaseName in "$listOfNames" # <-- Note: Added "" quotes.
do
echo "$databaseName" # (i.e. do action / processing of $databaseName here...)
done

# Outputs
# RA
# RB
# R C
# RD



B. No whitespace in the names:


listOfNames="RA
RB
R C
RD"

for databaseName in $listOfNames # Note: No quotes
do
echo "$databaseName" # (i.e. do action / processing of $databaseName here...)
done

# Outputs
# RA
# RB
# R
# C
# RD



Notes


listOfNames="RA RB R C RD"



Other ways to bring in data include:



Read from stdin


# line delimited (each databaseName is stored on a line)
while read databaseName
do
echo "$databaseName" # i.e. do action / processing of $databaseName here...
done # <<< or_another_input_method_here


IFS='n'


IFS='r'


#!/bin/bash



Other Sources
(while read loop)





This creates impression that eol is used as string separators and, therefore, whitespaces are allowed within the strings. However, strings with whitespaces are further separated into substrings, which is very very bad. I think that this answer stackoverflow.com/a/23561892/1083704 is better.
– Val
Jul 11 '14 at 9:02





@Val, I added code comment with a reference to IFS. (For everyone, IFS lets one specify a specific delimiter, which allows other whitespace to be included in strings without being separated into substrings).
– user2533809
Jul 21 '14 at 23:43


IFS


IFS





This doesn't work for me. $databaseName just contains the whole list, thus does only a single iteration.
– AlikElzin-kilaka
Jul 18 '16 at 13:04



$databaseName





@AlikElzin-kilaka My answer below solves this problem so that the loop is run for every line of the string.
– Jamie
Oct 16 '16 at 22:00



Yes


for Item in Item1 Item2 Item3 Item4 ;
do
echo $Item
done



Output :


Item1
Item2
Item3
Item4



Over multiple lines


for Item in Item1
Item2
Item3
Item4
do
echo $Item
done



Output :


Item1
Item2
Item3
Item4




Simple list variable


List=( Item1 Item2 Item3 )



or


List=(
Item1
Item2
Item3
)



Display the list variable :


echo $List[*]



Out put :


Item1 Item2 Item3



Loop through the list:


for Item in $List[*]
do
echo $Item
done



Out put :


Item1
Item2
Item3



Create a function to go through a list:


Loop()
for item in $* ;
do
echo $item
done

Loop $List[*]



To preserve spaces ; single or double quote list entries and double quote list expansions :


List=(' Item 1 '
' Item 2'
' Item 3'
)
for item in "$List[@]";
do
echo "$item"
done



Output :


Item 1
Item 2
Item 3



Using the declare keyword (command) to create the list , which is technically called an array :


declare -a List=(
"element 1"
"element 2"
"element 3"
)
for entry in "$List[@]"
do
echo "$entry"
done



Out put :


element 1
element 2
element 3



Creating an associative array . A dictionary :


declare -A continent

continent[Vietnam]=Asia
continent[France]=Europe
continent[Argentina]=America

for item in "$!continent[@]";
do
printf "$item is in $continent[$item] n"
done



Output :


Argentina is in America
Vietnam is in Asia
France is in Europe



CVS variables or files in to a list .
Changing the internal field separator from a space , to what ever you want .
In the example below it is changed to a comma


List="Item 1,Item 2,Item 3"
Backup_of_internal_field_separator=$IFS
IFS=,
for item in $List;
do
echo $item
done
IFS=$Backup_of_internal_field_separator



Output :


Item 1
Item 2
Item 3



If need to number them :


`



this is called a back tick . Put the command inside back ticks .


`commend`



It is next to the number one on your keyboard and or above the tab key . On a standard american english language keyboard .


List=()
Start_count=0
Step_count=0.1
Stop_count=1
for Item in `seq $Start_count $Step_count $Stop_count`
do
List+=(Item_$Item)
done
for Item in $List[*]
do
echo $Item
done



Out put is :


Item_0.0
Item_0.1
Item_0.2
Item_0.3
Item_0.4
Item_0.5
Item_0.6
Item_0.7
Item_0.8
Item_0.9
Item_1.0



Becoming more familiar with bashes behavior :



Create a list in a file


cat <<EOF> List_entries.txt
Item1
Item 2
'Item 3'
"Item 4"
Item 7 : *
"Item 6 : * "
"Item 6 : *"
Item 8 : $PWD
'Item 8 : $PWD'
"Item 9 : $PWD"
EOF



Read the list file in to a list and display


List=$(cat List_entries.txt)
echo $List
echo '$List'
echo "$List"
echo $List[*]
echo '$List[*]'
echo "$List[*]"
echo $List[@]
echo '$List[@]'
echo "$List[@]"



BASH commandline reference manual : Special meaning of certain characters or words to the shell.





THIS IS WRONG. Needs to be "$List[@]" to be correct, with the quotes. $List[@] is wrong. $List[*] is wrong. Try List=( "* first item *" "* second item *" ) -- you'll get correct behavior for for item in "$List[@]"; do echo "$item"; done, but not from any other variant.
– Charles Duffy
May 4 at 19:36



"$List[@]"


$List[@]


$List[*]


List=( "* first item *" "* second item *" )


for item in "$List[@]"; do echo "$item"; done





Yes special chars do get interpreted , which may or may not be desirable . I updated the answer to include .
– FireInTheSky
May 27 at 10:57





I still would strongly suggest showing the more correct/robust approach first. Folks often take the first answer that looks like it'll work; if that answer has hidden caveats, they may only expose themselves later. (It's not just wildcards that are broken by lack of quoting; List=( "first item" "second item" ) will be broken into first, item, second, item as well).
– Charles Duffy
May 27 at 15:13



List=( "first item" "second item" )


first


item


second


item





You might also consider avoiding use of an example that might lead people to parse ls output, in contravention of best practices.
– Charles Duffy
May 27 at 15:16


ls





You're refuting claims I never made. I'm quite familiar with bash's quoting semantics -- see stackoverflow.com/tags/bash/topusers
– Charles Duffy
May 31 at 23:59




You can use the syntax of $arrayName[@]


$arrayName[@]


#!/bin/bash
# declare an array called files, that contains 3 values
files=( "/etc/passwd" "/etc/group" "/etc/hosts" )
for i in "$files[@]"
do
echo "$i"
done



This is also easy to read:


FilePath=(
"/tmp/path1/" #FilePath[0]
"/tmp/path2/" #FilePath[1]
)

#Loop
for Path in "$FilePath[@]"
do
echo "$Path"
done





This one is clear and worked for me (including with spaces and variable substitution in the FilePath array elements) only when I set the IFS variable correctly before the FilePath array definition: IFS=$'n' This may work for other solutions too in this scenario.
– Alan Forsyth
Jan 22 '16 at 12:41



IFS=$'n'



Surprised that nobody's posted this yet -- if you need the indices of the elements while you're looping through the array, you can do this:


arr=(foo bar baz)

for i in $!arr[@]
do
echo $i "$arr[i]"
done



Output:


0 foo
1 bar
2 baz



I find this a lot more elegant than the "traditional" for-loop style (for (( i=0; i<$#arr[@]; i++ ))).


for (( i=0; i<$#arr[@]; i++ ))



($!arr[@] and $i don't need to be quoted because they're just numbers; some would suggest quoting them anyway, but that's just personal preference.)


$!arr[@]


$i


listOfNames="db_one db_two db_three"
for databaseName in $listOfNames
do
echo $databaseName
done



or just


for databaseName in db_one db_two db_three
do
echo $databaseName
done



The declare array doesn't work for Korn shell. Use the below example for the Korn shell:


promote_sla_chk_lst="cdi xlob"

set -A promote_arry $promote_sla_chk_lst

for i in $promote_arry[*];
do
echo $i
done





try the code highlighter in the editor to make your code look good.
– dove
Nov 2 '12 at 19:39





Good to know, but this question is about bash.
– Brad Koch
May 20 '13 at 14:47





Who uses Korn? Ok band, but that's about it...
– Mike Purcell
Nov 5 '15 at 16:40





Lotsa bugs here. Can't have list entries with spaces, can't have list entries with glob characters. for i in $foo[*] is basically always the wrong thing -- for i in "$foo[@]" is the form that preserves the original list's boundaries and prevents glob expansion. And the echo needs to be echo "$i"
– Charles Duffy
Jul 9 '16 at 15:00



for i in $foo[*]


for i in "$foo[@]"


echo "$i"



In addition to anubhava's correct answer: If basic syntax for loop is:


for var in "$arr[@]" ;do ...$var... ;done



there is a special case in bash:



When running a script or a function, arguments passed at command lines will be assigned to $@ array variable, you can access by $1, $2, $3, and so on.


$@


$1


$2


$3



This can be populated (for test) by


set -- arg1 arg2 arg3 ...



A loop over this array could be written simply:


for item ;do
echo "This is item: $item."
done



Note that the reserved work in is not present and no array name too!


in



Sample:


set -- arg1 arg2 arg3 ...
for item ;do
echo "This is item: $item."
done
This is item: arg1.
This is item: arg2.
This is item: arg3.
This is item: ....



Note that this is same than


for item in "$@";do
echo "This is item: $item."
done


#!/bin/bash

for item ;do
printf "Doing something with '%s'.n" "$item"
done



Save this in a script myscript.sh, chmod +x myscript.sh, then


myscript.sh


chmod +x myscript.sh


./myscript.sh arg1 arg2 arg3 ...
Doing something with 'arg1'.
Doing something with 'arg2'.
Doing something with 'arg3'.
Doing something with '...'.


myfunc() for item;do cat <<<"Working about '$item'."; done ;



Then


myfunc item1 tiem2 time3
Working about 'item1'.
Working about 'tiem2'.
Working about 'time3'.



If you are using Korn shell, there is "set -A databaseName ", else there is "declare -a databaseName"



To write a script working on all shells,


set -A databaseName=("db1" "db2" ....) ||
declare -a databaseName=("db1" "db2" ....)
# now loop
for dbname in "$arr[@]"
do
echo "$dbname" # or whatever

done



It should be work on all shells.





Nope, it doesn't: $ bash --version GNU bash, version 4.3.33(0)-release (amd64-portbld-freebsd10.0) $ set -A databaseName=("db1" "db2" ....) || declare -a databaseName=("db1" "db2" ....) bash: syntax error near unexpected token `('
– Bernie Reiter
Jan 17 '17 at 19:47



$ bash --version


$ set -A databaseName=("db1" "db2" ....) || declare -a databaseName=("db1" "db2" ....)



Simple way :


arr=("sharlock" "bomkesh" "feluda" ) ##declare array

len=$#arr[*] # it returns the array length

#iterate with while loop
i=0
while [ $i -lt $len ]
do
echo $arr[$i]
i=$((i+1))
done


#iterate with for loop
for i in $arr
do
echo $i
done

#iterate with splice
echo $arr[@]:0:3



This is similar to user2533809's answer, but each file will be executed as a separate command.


#!/bin/bash
names="RA
RB
R C
RD"

while read -r line; do
echo line: "$line"
done <<< "$names"



Possible first line of every Bash script/session:


say() for line in "$@" ; do printf "%sn" "$line" ; done ;



Use e.g.:


$ aa=( 7 -4 -e ) ; say "$aa[@]"
7
-4
-e



May consider: echo interprets -e as option here


echo


-e



Single line looping,


declare -a listOfNames=('db_a' 'db_b' 'db_c')
for databaseName in $listOfNames[@]; do echo $databaseName; done;



you will get an output like this,


db_a
db_b
db_c



Try this. It is working and tested.


for k in "$array[@]"
do
echo $k
done

# For accessing with the echo command: echo $array[0], $array[1]





This does not actually work correctly. Try array=( "hello world" ), or arrray=( "*" ); in the first case it will print hello and world separately, in the second it will print a list of files instead of the *
– Charles Duffy
Jul 9 '16 at 14:55



array=( "hello world" )


arrray=( "*" )


hello


world


*





...before calling something "tested" in shell, be sure to check the corner cases, which whitespace and globs are both among.
– Charles Duffy
Jul 9 '16 at 14:58



I loop through an array of my projects for a git pull update:


git pull


#!/bin/sh
projects="
web
ios
android
"
for project in $projects do
cd $HOME/develop/$project && git pull
end





While this code snippet may solve the question, including an explanation really helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion. Please also try not to crowd your code with explanatory comments, this reduces the readability of both the code and the explanations!
– kayess
Dec 8 '16 at 8:37




Thank you for your interest in this question.
Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).



Would you like to answer one of these unanswered questions instead?

Popular posts from this blog

𛂒𛀶,𛀽𛀑𛂀𛃧𛂓𛀙𛃆𛃑𛃷𛂟𛁡𛀢𛀟𛁤𛂽𛁕𛁪𛂟𛂯,𛁞𛂧𛀴𛁄𛁠𛁼𛂿𛀤 𛂘,𛁺𛂾𛃭𛃭𛃵𛀺,𛂣𛃍𛂖𛃶 𛀸𛃀𛂖𛁶𛁏𛁚 𛂢𛂞 𛁰𛂆𛀔,𛁸𛀽𛁓𛃋𛂇𛃧𛀧𛃣𛂐𛃇,𛂂𛃻𛃲𛁬𛃞𛀧𛃃𛀅 𛂭𛁠𛁡𛃇𛀷𛃓𛁥,𛁙𛁘𛁞𛃸𛁸𛃣𛁜,𛂛,𛃿,𛁯𛂘𛂌𛃛𛁱𛃌𛂈𛂇 𛁊𛃲,𛀕𛃴𛀜 𛀶𛂆𛀶𛃟𛂉𛀣,𛂐𛁞𛁾 𛁷𛂑𛁳𛂯𛀬𛃅,𛃶𛁼

Edmonton

Crossroads (UK TV series)