There are two types of bash for loops available. One using the “in” keyword with list of values, another using the C programming like syntax.
This article is part of our on-going bash tutorial series.
This explains both of the bash for loop methods, and provides 12 different examples on how to use the bash for loop in your shell scripts.
Bookmark this article for future reference, as this is the only article you would ever need to refer on how to use bash for loops with examples.
Method 1: Bash For Loop using “in” and list of values
Syntax:
for varname in list do command1 command2 .. done
In the above syntax:
- for, in, do and done are keywords
- “list” contains list of values. The list can be a variable that contains several words separated by spaces. If list is missing in the for statement, then it takes the positional parameter that were passed into the shell.
- varname is any Bash variable name.
In this form, the for statement executes the commands enclosed in a body, once for each item in the list. For example, if the list of values contains 5 items, the for loop will be executed a total of 5 times, once for each item in the list. The current item from the list will be stored in a variable “varname” each time through the loop. This “varname” can be processed in the body of the for loop.
Method 2: Bash For Loop using C like syntax
The second form of the for loop is similar to the for loop in “C” programming language, which has three expressions (initialization, condition and updation).
for (( expr1; expr2; expr3 )) do command1 command2 .. done
In the above bash for command syntax,
- Before the first iteration, expr1 is evaluated. This is usually used to initialize variables for the loop.
- All the statements between do and done are executed repeatedly until the value of expr2 is TRUE.
- After each iteration of the loop, expr3 is evaluated. This is usually used to increment a loop counter.
The following 12 examples shows how to bash for loops in different ways.
1. Static values for the list after “in” keyword
In the following example, the list of values (Mon, Tue, Wed, Thu and Fri) are directly given after the keyword “in” in the bash for loop.
$ cat for1.sh i=1 for day in Mon Tue Wed Thu Fri do echo "Weekday $((i++)) : $day" done $ ./for1.sh Weekday 1 : Mon Weekday 2 : Tue Weekday 3 : Wed Weekday 4 : Thu Weekday 5 : Fri
Caution: The list of values should not be separated by comma (Mon, Tue, Wed, Thu, Fri). The comma will be treated as part of the value. i.e Instead of “Mon”, it will use “Mon,” as value as shown in the example below.
$ cat for1-wrong1.sh i=1 for day in Mon, Tue, Wed, Thu, Fri do echo "Weekday $((i++)) : $day" done $ ./for1-wrong1.sh Weekday 1 : Mon, Weekday 2 : Tue, Weekday 3 : Wed, Weekday 4 : Thu, Weekday 5 : Fri
Caution: The list of values should not be enclosed in a double quote. (“Mon Tue Wed Thu Fri”). If you enclose in double quote, it will be treated as a single value (instead of 5 different values), as shown in the example below.
$ cat for1-wrong2.sh i=1 for day in "Mon Tue Wed Thu Fri" do echo "Weekday $((i++)) : $day" done $ ./for1-wrong2.sh Weekday 1 : Mon Tue Wed Thu Fri
2. Variable for the list after “in” keyword
Instead of providing the values directly in the for loop, you can store the values in a variable, and use the variable in the for loop after the “in” keyword, as shown in the following example.
$ cat for2.sh i=1 weekdays="Mon Tue Wed Thu Fri" for day in $weekdays do echo "Weekday $((i++)) : $day" done $ ./for2.sh Weekday 1 : Mon Weekday 2 : Tue Weekday 3 : Wed Weekday 4 : Thu Weekday 5 : Fri
Caution: As a best practice, you should always quote the bash variables when you are referring it. There are few exceptions to this best practice rule. This is one of them. If you double quote the variable in this for loop, the list of values will be treated as single value. Lot of people fall into this trap. Be careful and do not double quote your variable in the for loop.
$ cat for2-wrong.sh i=1 weekdays="Mon Tue Wed Thu Fri" for day in "$weekdays" do echo "Weekday $((i++)) : $day" done $ ./for2-wrong.sh Weekday 1 : Mon Tue Wed Thu Fri
3. Don’t specify the list; get it from the positional parameters
If you don’t specify the keyword “in” followed by any list of values in the bash for loop, it will use the positional parameters (i.e the arguments that are passed to the shell script).
$ cat for3.sh i=1 for day do echo "Weekday $((i++)) : $day" done $ ./for3.sh Mon Tue Wed Thu Fri Weekday 1 : Mon Weekday 2 : Tue Weekday 3 : Wed Weekday 4 : Thu Weekday 5 : Fri
Caution: Please be careful if you use this method. You should not include the keyword “in” in the for loop. If you leave the keyword “in” without any values, it will not use the positional parameter as shown below. It will not go inside the loop. i.e for loop will never get executed as shown in the example below.
$ cat for3-wrong.sh i=1 for day in do echo "Weekday $((i++)) : $day" done $ ./for3-wrong.sh Mon Tue Wed Thu Fri
Note: Refer to our earlier article to understand more about bash positional parameters.
4. Unix command output as list values after “in” keyword
You can use the output of any UNIX / Linux command as list of values to the for loop by enclosing the command in back-ticks ` ` as shown below.
$ cat for4.sh i=1 for username in `awk -F: '{print $1}' /etc/passwd` do echo "Username $((i++)) : $username" done $ ./for4.sh Username 1 : ramesh Username 2 : john Username 3 : preeti Username 4 : jason ..
5. Loop through files and directories in a for loop
To loop through files and directories under a specific directory, just cd to that directory, and give * in the for loop as shown below.
The following example will loop through all the files and directories under your home directory.
$ cat for5.sh i=1 cd ~ for item in * do echo "Item $((i++)) : $item" done $ ./for5.sh Item 1 : positional-parameters.sh Item 2 : backup.sh Item 3 : emp-report.awk Item 4 : item-list.sed Item 5 : employee.db Item 8 : storage Item 9 : downloads
Usage of * in the bash for loop is similar to the file globbing that we use in the linux command line when we use ls command (and other commands).
For example, the following will display all the files and directories under your home directory. This is the concept that is used in the above for5.sh example.
cd ~ ls *
The following will display all the *.conf file that begins with either a, b, or, c or d under /etc directory.
$ ls -1 /etc/[abcd]*.conf /etc/asound.conf /etc/autofs_ldap_auth.conf /etc/cas.conf /etc/cgconfig.conf /etc/cgrules.conf /etc/dracut.conf
The same argument that is used in the ls command above, can be used in a bash for loop, as shown in the example below.
$ cat for5-1.sh i=1 for file in /etc/[abcd]*.conf do echo "File $((i++)) : $file" done $ ./for5-1.sh File 1 : /etc/asound.conf File 2 : /etc/autofs_ldap_auth.conf File 3 : /etc/cas.conf File 4 : /etc/cgconfig.conf File 5 : /etc/cgrules.conf File 6 : /etc/dracut.conf
6. Break out of the for loop
You can break out of a for loop using ‘break’ command as shown below.
$ cat for6.sh i=1 for day in Mon Tue Wed Thu Fri do echo "Weekday $((i++)) : $day" if [ $i -eq 3 ]; then break; fi done $ ./for6.sh Weekday 1 : Mon Weekday 2 : Tue
7. Continue from the top of the for loop
Under certain conditions, you can ignore the rest of the commands in the for loop, and continue the loop from the top again (for the next value in the list), using the continue command as shown below.
The following example adds “(WEEKEND)” to Sat and Sun, and “(weekday)” to rest of the days.
$ cat for7.sh i=1 for day in Mon Tue Wed Thu Fri Sat Sun do echo -n "Day $((i++)) : $day" if [ $i -eq 7 -o $i -eq 8 ]; then echo " (WEEKEND)" continue; fi echo " (weekday)" done $ ./for7.sh Day 1 : Mon (weekday) Day 2 : Tue (weekday) Day 3 : Wed (weekday) Day 4 : Thu (weekday) Day 5 : Fri (weekday) Day 6 : Sat (WEEKEND) Day 7 : Sun (WEEKEND)
8. Bash for loop using C program syntax
This example uses the 2nd method of bash for loop, which is similar to the C for loop syntax. The following example generates 5 random number using the bash C-style for loop.
$ cat for8.sh for (( i=1; i <= 5; i++ )) do echo "Random number $i: $RANDOM" done $ ./for8.sh Random number 1: 23320 Random number 2: 5070 Random number 3: 15202 Random number 4: 23861 Random number 5: 23435
9. Infinite Bash for loop
When you don’t provide the start, condition, and increment in the bash C-style for loop, it will become infinite loop. You need to press Ctrl-C to stop the loop.
$ cat for9.sh i=1; for (( ; ; )) do sleep $i echo "Number: $((i++))" done
Like we said above, press Ctrl-C to break out of this bash infinite for loop example.
$ ./for9.sh Number: 1 Number: 2 Number: 3
10. Using comma in the bash C-style for loop
In the bash c-style loop, apart from increment the value that is used in the condition, you can also increment some other value as shown below.
In the initialize section, and the increment section of the bash C-style for loop, you can have multiple value by separating with comma as shown below.
The following for loop is executed a total of 5 times, using the variable i. However the variable j start with 5, and getting increment by 5 every time the loop gets executed.
$ cat for10.sh for ((i=1, j=10; i <= 5 ; i++, j=j+5)) do echo "Number $i: $j" done $ ./for10.sh Number 1: 10 Number 2: 15 Number 3: 20 Number 4: 25 Number 5: 30
11. Range of numbers after “in” keyword
You can loop through using range of numbers in the for loop “in” using brace expansion.
The following example loops through 10 times using the values 1 through 10.
$ cat for11.sh for num in {1..10} do echo "Number: $num" done $ ./for11.sh Number: 1 Number: 2 Number: 3 Number: 4 Number: 5 ...
12. Range of numbers with increments after “in” keyword
The following example loops through 5 times using the values 1 through 10, with an increment of 2. i.e It starts with 1, and keeps incrementing by 2, until it reaches 10.
$ cat for12.sh for num in {1..10..2} do echo "Number: $num" done $ ./for12.sh Number: 1 Number: 3 Number: 5 Number: 7 Number: 9
PS: Don’t forget to bookmark this article for your future reference.
Comments on this entry are closed.
Hi,
Really, very nice article
Thanks a lot…
when I run for8.sh
I get error
“for8.sh: 3: Syntax error: Bad for loop variable”
I use Ubunutu 11.04
I did cut and paste the code , did not modify anything
such many way
( ⊙ o ⊙ )!
@Joseph John . . .for8.sh works for me….using bash shell
Thanks Ramesh!
I knew all bash loops you showed, is great to see them joined in one page. This helps so much whom is learning this useful language. 🙂
Regards,
Júlio.
@Marija , I tried using bash “for8.sh” and it is working
thanks
Good one…will use most of examples in practical….
cat for12.sh
for num in {1..10..2}
do
echo “Number: $num”
done
Above example is not working….
Output is comming as follows…..
for num in {1..10..2}
quote” Kamal Kishore”
cat for12.sh
for num in {1..10..2}
do
echo “Number: $num”
done
Above example is not working….
Output is comming as follows…..
for num in {1..10..2}
thanks Ramesh,
I knew the “classic” bash syntax (but it is always good to pop up some old knowledge) but i totally discovered the “C” style syntax!
I won’t bookmark this page as i already bookmarked your site!
for num in {1..10..2}
do
echo “Number: $num”
done
under bash is working
output is:
“Number: 1”
“Number: 3”
“Number: 5”
“Number: 7”
“Number: 9”
I always disliked bash, but at least it has some good bits.
Though I doubt it that it will be the next javascript (a language which was very much disliked by everyone in the early days but gains some popularity now).
A simpler variation of the infinite for loop:
$ cat for9-a.sh
i=1;
for :
do
sleep $i
echo “Number: $((i++))”
done
About the ” Syntax error: Bad for loop variable”
Be sure to use BASH and not SH as interpreter
Correction to my earlier post. The alternate infinite for loop using the : (nop) operator must be while, not for. i.e.
while :
do
sleep $i
echo “Number: $((i++))”
done
For those using Ubuntu, be aware that Dash is the symbolic link for sh instead of the traditional Bash. For other distros, you can test this using
ls -l `which sh`
and if it is dash, you can change it back to bash with
cd /bin
sudo rm sh
sudo ln -s bash sh
You’re the best 😀
Gr8 Article f 🙂
One thing you left off was the one line format:
$ for foo in a b c ; do echo $foo; done
Note the added semi-colons indicating the end of each statement.
Hi Friends,
I tried for loop as below.
for i in {“$start”..”$end”}
where start and end are user input variable. Its throwing error as:
syntax error: operand expected (error token is “{2..5}”)
Please help me where I have to give this operand ‘(‘.
Looking for your reply.
Thanks
Varun S
eval for i in {$start..$end}\;do echo \$i\;done
Hi ramesh/team,
how to use multiple variable in single “for” loop .if not possible pls give alternate solution .
i am trying
for file in $(cat 2) && for ID in $(cat 3)
do
echo “Modifying file : $file and $ID ”
echo “” >> $file.tmp
cat $file >> $file.tmp
mv $file.tmp $file
done
But Not working .
please help me on this.
thanks in advance
Rajesh /JDHP
@Ken Butcher Thanks a lot for your comment … i had a project deadline .. and was struck doing the benchmarks with the error bad loop variable … after doing the change you have given , I got it solved.. again thanks a lot…
@Ramesh clean and simple… great article
Awsome examples…and use almost every day..great job !!!
What about for adding numbers to the end of a file if it is already detected while being copied?
ex. copy file 1
ok
copy file 1 again
file one renamed as file 1(2)
ect..
google bash backup version control
for i in {$start..$end}
do
echo ” i m $i”
done
where start and end are user input variable,
Above example is not working……
output is – i m 2..7
as 2 and 7 are the user inputs…………
Pls help me ……….
shweta,
Bash doesn’t work that way. you can use {2..7} but not {$a..$b}
A work around is
for (( i=$start; i<=$end; i++ ))
do
echo ” i m $i”
done
@ MAine_guy thanks………. it solved my confusions………
Another way:
for i in $(seq $start $end); do
echo “i m $i”
done
all info abt for loop…….i got it……..thanks….
I’ve never been able to get bracket expansion to work in a loop…
somaddict@terrordome ~/sandbox
$ for i in [abcd] ; do echo $i;done
[abcd]
somaddict@terrordome ~/sandbox
$ for i in {a..d}; do echo $i;done
a
b
c
d
i want shell script programs from simple to complex..
if u guys help me it will be useful for me..
very thanks in advance
Im trying to run each comand then the next one in a loop. im getting an error?
/etc/init.d/FMtx.sh: 3: /etc/init.d/FMtx.sh: Syntax error: Bad for loop variable
???
—————————
#!/bin/sh
for ((i=0;i<6;i++))
do
sudo /home/pi/pifm botID.wav 90.3
sudo /home/pi/pifm nightlife_01.wav 90.3
sudo /home/pi/pifm –
sudo /home/pi/pifm wwrob2.wav 90.3
sudo /home/pi/pifm –
sudo /home/pi/pifm mae.wav 90.3
echo $i
done
—————————–
Mathisin, Change #!/bin/sh to #!/bin/bash and your script will run without error.
/bin/sh used to be a symbolic link to /bin/bash but now it is a symbolic link to /bin/dash
Hi I need to use like this
for i in $list j in $list1
do
done
may i know is there any chance like this
thank you
in solaris 10
for i in {1..254}; do ping 172.20.140.$i 1 |grep alive;done
Many thanks for the help. From this page I got all the information I was searching for my script.
I really found these examples very helpful for those who are beginners in Shell Scripting using both bash and sh. Personnaly, it has helped me to better understand For Loops in Shell Scripts.
Thank you very must for posting those kinds of knowlege online.
Below code executed successfull but output will be not generated.. even its not print echo $var also. Where is it wrong. Similar as your example Number 4. Please help..
for var in `ps –help|grep Try|cut -d’>psoption
done
Can anyone tell me ..i am using for loop in ksh …but i want to use without seq
for (( i=$start; i<=$end; i++ ))
do
echo ” i m $i”
done
bt not working
sahil: see my comment above about bash vs. sh. Your code works in bash but not in sh
nice articles, do you have any other posting for other loops like while and arithmetic operations, file handling etc.
@@@@ Sahil
for (( i=1; i<=10 ;i++ )) ; do echo "i m $i" ;done
Backing up files
for i in ls * ; do echo “Backing up file: $i”; cp $i $i.bak; done
i=1
for file in `awk -F: ‘{print $1}’ /praksh/[abcd]*.xml`
do
echo “File $((i++)) : $file”
done
Could you please i have issue on the above script ?
Error: gawk: cmd. line:2: fatal: cannot open file `/praksh/[abcd]*.xml’ for reading (No such file or directory)
Awesome tutorial..
only this did not worked.
i=1
for day
do
echo “Weekday $((i++)) : $day”
done
I have this script saved as /usr/local/bin/timenow.sh and it contains the following:
#!/bin/bash
d1=”$(date +”%d-%b-%Y”)”;
t1=”$(date +”%l:%M %p”)”;
da1=”$(date +”%A”)”;
eval “export $(egrep -z DBUS_SESSION_BUS_ADDRESS /proc/$(pgrep -u $LOGNAME xfce4-session)/environ)”;
/usr/bin/notify-send “Date & Time reminder:” “$d1 \n””$t1 \n””$da1” -i “/usr/share/pixmaps/gnome-computer.png” -t 9000;
exit 0;
I have add the cron job for this script to run every day at 5pm to alert users of the logout time and it works fine. But this is working only for for a single user because i manually set it as a cron job for this parituclar user. Most users are connected remotely to this ubuntu server (LTSP environment) and so I need to configure the crontab through root user in such a way that it must alert every logged in user on the server. Any help please? If there’s a possible way to run this script as a root user and call the DBUS_SESSION_BUS_ADDRESS of each logged in user and set them in an array and execute it in a loop until it shows the notification to all the logged in user sessions or any other method?
How to print a series 1 -2 3 -4 5 -6 7
Explanation is very good and flaw less. I always like your articles. Please keep posting.
good article
Neither of these methods working. every time i try to work run these scripts i get “./week.sh[5]: i++: more tokens expected” this error
The braces will expand leading zeros (with a current bash).
So:
$ for i in {000..1}; do echo $i; done
Will expand to:
000
001
But variables will expand to string thusly:
some_input=1=3000
for i in {000..$some_input}; do echo $i; done
results in a string, not an array expansion. Thus the output is:
{000..3000}
As mentioned: Using eval will work, but is messy for multi-line code.