In the previous post, we talked about how to write a bash script, and we saw how bash scripting is awesome. In this post, we will look at the for command, while command, and how to make loops to iterate over a series of values. The for command enables you to perform a loop on a list of items. This is often the fundamental format of the for command.
for myvar in vars
do
Code Here
done
In every loop, the variable myvar holds one of the values of the list. The loop iterates until the list is finished.
Iterating Over Simple Values
You can iterate over simple values like this:
#!/bin/bash
for var in first second third fourth fifth
do
echo The $var item
done
Check the results:
Iterating Over Complex Values
Your list maybe contains a comma or two words, and you want to deal with them as one item on the list.
Check the following example:
#!/bin/bash
for var in first "the second" "the third" "I’ll do it"
do
echo "This is: $var"
done
We quote our strings with double quotations.
We play nice till now, we always do. Just keep reading and practicing.
Command Substitution
By using command substitution using this format $(Linux command) you can store the result in a variable for later use.
#!/bin/bash
my_file="myfile"
for var in $(cat $my_file)
do
echo " $var"
done
Here we get the file content using cat command. Notice that our file contains one word per line, not separated by spaces.
Here we get the content of the file using command substitution then iterate over the result, assuming that each line has one word.
What about having spaces in one of these lines?
In this case, every word will be considered a field. You need to tell the shell to consider new lines as a separator instead of spaces.
The Field Separator
By default, the following characters treated as fields.
- Space
- Tab
- newline
If your text includes any of these characters, the shell will assume it’s a new field.
Well, you can change the internal field separator or IFS environment variable. like this:
IFS=$'\n'
It will consider new lines as a separator instead of spaces.
#!/bin/bash
file="/etc/passwd"
IFS=$'\n'
for var in $(cat $file)
do
echo " $var"
done
You got it. Bash scripting is easy.
The separator is colons in /etc/passwd file which contains the user’s information, you can assign it like this:
IFS=:
Bash scripting is awesome, right?
Iterating Over Directory Files
If you want to list the files in /home directory, you can use the for loop like this:
#!/bin/bash
for obj in /home/likegeeks/*
do
if [ -d "$obj" ]
then
echo "$obj is a folder"
elif [ -f "$obj" ]
then
echo "$obj is a file"
fi
done
From the previous post, you should know the if statement and how to check for files and folders, so if you don’t know, I recommend you to review it bash script step by step.
Here we use wildcard character which is the asterisk * and this is called in bash scripting file globbing which means All files with all names.
Notice that in the if statements here we quote our variables with quotations because maybe the file or the folder name contains spaces.
As you see the result, all files and directories in that folder are listed.
for Command C-Style
If you know C language, you may find that the for loop here is some weird because you are familiar with this syntax:
for (var= 0; var < 5; var++)
{
printf(“number is %d\n”, var);
}
Well, you can use the same syntax but with a little difference, here’s the syntax.
for (( variable = start ; condition ; iteration step))
So it looks like this:
for (( var = 1; var < 5; var++ ))
And this is an example:
#!/bin/bash
for (( var=1; var <= 10; var++ ))
do
echo "number is $var"
done
And this is the output:
The while Command
The for loop is not the only way for looping in bash scripting. The while loop does the same job but it checks for a condition before every iteration.
The while loop command takes the following structure:
while condition
do
commands
done
and here is an example:
#!/bin/bash
number=10
while [ $number -gt 4 ]
do
echo $number
number=$[ $number - 1 ]
done
The script is simple; it starts with the while command to check if number is greater than zero, then the loop will run and the number value will be decreased every time by 1 and on every loop iteration it will print the value of number, Once the number value is zero the loop will exit.
If we don’t decrease the value of var1, it will be the same value and the loop will be infinite.
Nesting Loops
You can type loops inside loops. This is called the nested loop.
Here’s an example of nested loops:
#!/bin/bash
for (( v1 = 1; v1 <= 5; v1++ ))
do
echo "Start $v1:"
for (( v2 = 1; v2 <= 5; v2++ ))
do
echo " Inner loop: $v2"
done
done
The outer loop hits first, then goes into the internal loop and completes it and go back to the outer loop and so on.
Iterate Over File Content
This is the most common usage for the for loop in bash scripting.
We can iterate over file content, for example, iterate over /etc/passwd file and see the output:
#!/bin/bash
IFS=$'\n'
for text in $(cat /etc/passwd)
do
echo "This line $text ++ contains"
IFS=:
for field in $text
do
echo " $field"
done
done
Here we have two loops, the first loop iterate over the lines of the file and the separator is the newline, the second iteration is over the words on the line itself and the separator is the colon :
You can apply this idea when you have a CSV or any comma separated values file. The idea is the same; you just have to change the separator to fit your needs.
Controlling the Loop
Maybe after the loop starts you want to stop at a specific value, will you wait until the loop is finished? Of course no, there are two commands help us in this:
- break command
- continue command
The break Command
The break command is used to exit from any loop, like the while and the until loop
#!/bin/bash
for number in 10 11 12 13 14 15
do
if [ $number -eq 14 ]
then
break
fi
echo "Number: $number"
done
The loop runs until it reaches 14 then the break command exits the loop.
And the same for the while loop:
#!/bin/bash
val=1
while [ $val -lt 5 ]
do
# Check number value
if [ $val -eq 4 ]
then
# The Code Breaks here <==
break
fi
# The Printed Message
echo "Iteration: $val"
val=$(( $val + 1 ))
done
The break command exits the while loop and that happens when the execution reaches the if statement.
The continue command
You can use the continue command to stop executing the remaining commands inside a loop without exiting the loop.
Check the following example:
#!/bin/bash
# The loop starts here
for (( number = 1; number < 10; number++ ))
do
# Check if number greater than 0 and less than 5
if [ $number -gt 0 ] && [ $number -lt 5 ]
then
continue
fi
# The printed message
echo "Iteration number: $number"
done
When the if condition is true, the continue command runs each iteration, and lines after the continue command never run until the condition becomes false.
Redirecting the Loop Output
You can use the done command to send the loop output to a file like this:
#!/bin/bash
for (( var = 1; var < 10; var++ )) do echo "Number is $var" done > myfile.txt
echo "finished."#!/bin/bash
for (( var = 1; var < 10; var++ )) do echo "Number is $var" done > myfile.txt
echo "finished."
The shell creates the file myfile.txt and the output is redirected to the file, and if we check that file we will find our loop output inside it.
Let’s employ our bash scripting knowledge in something useful.
Useful Examples
Finding executables
To get all executable files on your system, you can iterate over the directories in the PATH variable. We discussed for loop and if statements and file separator so our toolset is ready. Let’s combine them together and make something useful.
#!/bin/bash
IFS=:
for dir in $PATH
do
echo "$dir:"
for myfile in $dir/*
do
if [ -x $myfile ]
then
echo " $myfile"
fi
done
done
This is just awesome. We were able to get all the executables on the system that we can run.
Now nothing stops you except your imagination.
I hope you learn a new thing or at least review your knowledge if you forget it. My last word for you, keep reading and practicing.
Thank you.