For loops for, in, do, done

Loops are used to execute the a statement of tasks a repeated number of times or until a condition is met. There are two types of loops used in shell scripting - the for and while loops. Let's start with the for loop, which can take on a variety of tasks.

Keywords

The keywords used in a for-loop are for , in , do , and done . Here is the structure for a for-loop.

for variableName in list do some commands done

1) Iterate through a list

One way to run through a for loop is to iterate through a list. This list may consist of strings or numbers.

#!/bin/bash for food in "bbq" "french fries" "coleslaw" do echo "I like $food." done p | Here's the output: pre code.lang-bash $ ./test I like bbq. I like french fries. I like coleslaw.

Remember that with brace expansions, you can list a range of numbers or letters.

#!/bin/bash printf "Press enter to launch rocket ship: " read for num in {5..1} do echo "$num..." sleep 1 done for rocket in 'Blastoff!' ' A ' ' / \ ' ' | |=| ' ' | | ' ' | | ' ' _|=|_ ' ' / | | \ ' | ' | \,/ | ' ' |/" "\| ' ' """"""" ' do echo "$rocket" sleep 1 done

Try copying and pasting this code snippet and running it to see a rocketship blast off!

2) Repeat per output of a command

You may also loop through outputs of a command.

#!/bin/bash count=1 for output in $(ls) do printf "File %2d: %s

" $count $output ((count=count+1)) done

This script simply takes the output of an ls command and lists them in order with an integer marking its position.

$ ./test File 1: Applications File 2: Desktop File 3: Documents File 4: Downloads File 5: Dropbox File 6: Library File 7: Movies File 8: Music File 9: Pictures File 10: Public

3) Three-step for loops

In most programming language, there are three-step for loops. The first expression is the variable declaration, the second is the loop condition test and the third is some evaluation that updates the expression.

To use such a three-step for loop in shell scripting, use the following syntax:

#!/bin/bash for (( i=1; i <= 5; i++ )) do echo "$i Mississippi..." sleep 1 done echo "Ready or not here I come!"

The result is simply:

$ ./test 1 Mississippi... 2 Mississippi... 3 Mississippi... 4 Mississippi... 5 Mississippi... Ready or not here I come!

To get an inifinite loops, simply omit all three placeholders.

#!/bin/bash for (( ; ; )) do echo "ctrl+c to stop this runaway infinite loop!" done

4) Looping over command line arguments

If you remember from our previous tutorial, the $@ variable stores all command line arguments. We can thus use the $@ as a list and loop over our arguments.

However, placing the $@ is optional. By default, the in $@ is already included.

#!/bin/bash for i do case $i in -v) verbose=1 quiet= ;; -q) quiet=1 verbose= ;; esac done

5) Looping specific files within directory

We can also use a for loop to iterate through items of a directory. Here, we take all text files within the current directory and stitch them together.

#!/bin/bash for file in ./* do if [ ${file: -4} == ".txt" ] then cat $file >> concatFile.txt fi done

While and until loops while, do, done

while loops

While-loops are much like for-loops, and continue to iterate until the exit status of the condition is false. While-loops consist of the following syntax:

while [ condition exits successfully ] do # Commands here done

Using shift to iterate through shell arguments

A common use of the while-loop is to iterate through shell arguments, to obtain all option arguments. Each call to the shift command helps us go down the list of options, with the arguments going down one by one. This causes the value of $1 to be replaced by $2 , $2 to be replaced by $3 , and so on.

Here's a script of how we can combine a while-loop with a case-statement to iterate through all options.

#!/bin/bash while [ $# -gt 0 ] do case $1 in # File option, followed by filename -f) filename=$2 shift ;; -v) verbose=true quiet= ;; -q) quiet=true verbose= ;; -l) long=true ;; # Unrecognized option -*) echo "$0: $1: unrecognized option" <&2 ;; **) break ;; esac # shift for next option shift done

Getting option parameters with getopts

Another helpful command that is often seen with while-loops is getopts . This command follows standard POSIX option syntax (single letters preceded by a - and possibly one argument value).

For each option that contains an argument, we use the colon ( : ). For example, we can have a:bc if we plan to have the -a option contain an argument. An example call would look something like:

$ ./test -a argumentValue -b -b

Thus the argumentValue goes with the -a option.

In this example, we design a timer that has several options a user can specify.

#!/bin/bash if [ $# -lt 1 ] then echo "Usage: $0 -t -m -a -r" echo "-t time (in seconds)" echo "-m message at countdown" echo "-a author" echo "-r repeat n number of times" exit 1 fi # Set default parameters seconds=5 message="Time's up!" author="anonymous" repeatNumber=1 # Need to have a colon (:) after each option that has | an argument. while getopts t:m:a:r: opt do case $opt in t) seconds=$OPTARG;; m) message=$OPTARG;; a) author=$OPTARG;; r) repeatNumber=$OPTARG;; esac done for iterationNumber in $(seq 1 $repeatNumber) do echo "Repeating $iterationNumber of $repeatNumber | times!" for sec in $(seq $seconds 1) do echo "Countdown: $sec" sleep 1 done done echo "$message by $author"

Until loops until, do, done

Until loops are very similar to while loops except they run as long as the exit status of the condition is unsuccessful.

until [ condition exits successfully ] do # Commands here done

A simple example - counting up to 10

Here is a quick example that runs the until loop until our value is greater than 10.

#!/bin/bash value=1 until [ ! $value -le 10 ] do echo "$value is not yet greater than 10." ((value=$value+1)) done echo "$value is now greater than 10!"

Looping control flow continue, break

In cases of exceptions, where we find that we want to direct the flow of the loop back to the test condition or break out of it, we can use two commands - continue and break .

continue

The continue keyword is used to ignore the rest of the statements for that loop iteration, and go back to the test condition.

This short script breaks forces the loop to go back to the condition when $var is equal to 5. Thus, the output would print out all values up to 10 except 5.

#!/bin/bash for var in {1..10} do if [ $var -eq 5 ] then continue; fi echo "$var" done

$ ./test 1 2 3 4 6 7 8 9 10

break

To break out of a loop, simply use the command break .

If there is more than one loop you want break out of, you can specify a value after the keyword.

#!/bin/bash for iter in {2..4} do for var in {1..10} do if [ $var -eq 5 ] then break 2; fi echo $(($iter * $var)) done done