Bash scripts: start
Bash scripts, part 2: loops
Bash scripts, part 3: command line options and keys
Bash scripts, part 4: input and output
Bash Scripts, Part 5: Signals, Background Tasks, Script Management
Bash scripts, part 6: functions and library development
Bash scripts, part 7: sed and word processing
Bash scripts, part 8: awk data processing language
Bash scripts, part 9: regular expressions
Bash scripts, part 10: practical examples
Bash scripts, part 11: expect and automate interactive utilities
Last time, we talked about the basics of programming for bash. Even the little that has already been disassembled, allows everyone to start automation of work in Linux. In this article we will continue the story about bash scripts, let's talk about control structures that allow you to perform repetitive actions. We are talking about
for
and
while
cycles, methods of working with them and practical examples of their use.
Attention: the benefits are hidden in the post!

')
For loops
The bash shell supports
for
loops that allow you to iterate through sequences of values. Here is the basic structure of such cycles:
for var in list do done
In each iteration of the loop, the next value from the list will be written to the
var
variable. In the first pass of the cycle, thus, the first value from the list will be activated. In the second - the second, and so on - until the cycle reaches the last element.
Enumerate simple values
Perhaps the simplest example of a
for
loop in bash scripts is to iterate through a list of simple values:
#!/bin/bash for var in first second third fourth fifth do echo The $var item done
Below are the results of this script. It is clearly seen that elements from the list are consistently placed in the
$var
variable. This happens until the cycle reaches the last of them.
Simple for loopPlease note that the
$var
variable saves the value when exiting the loop, its contents can be changed, in general, you can work with it as with any other variable.
Enumerate complex values
The list used to initialize the
for
loop can include not only simple single-word strings, but also whole phrases that include several words and punctuation marks. For example, all this might look like this:
#!/bin/bash for var in first "the second" "the third" "I'll do it" do echo "This is: $var" done
That's what happens after this cycle goes through the list. As you can see, the result is quite expected.
Enumerate complex valuesTNW-CUS-FMP - promotional code for a 10% discount on our services, available for activation within 7 days "Initialization of the cycle list received from the results of the team
Another way to initialize a
for
loop is to give it a list, which is the result of some command. It uses the substitution of commands for their execution and obtain the results of their work.
#!/bin/bash file="myfile" for var in $(cat $file) do echo " $var" done
In this example, the
cat
command is involved, which reads the contents of the file. The resulting list of values ​​is passed to the loop and displayed on the screen. Please note that the file we are referring to contains a list of words separated by new lines, spaces are not used.
A loop that iterates over the contents of a file.Here we must take into account that such an approach, if it is expected to have line-by-line data processing, will not work for a file of a more complex structure, the lines of which may contain several words separated by spaces. The loop will process individual words, not strings.
What if this is not at all what is needed?
Field separators
The reason for the above feature is a special environment variable called
IFS
(Internal Field Separator) that allows you to specify field separators. By default, the bash shell treats the following characters as field delimiters:
- Space
- Tab character
- Line break
If bash encounters any of these characters in the data, it considers that before it is the next independent meaning of the list.
In order to solve a problem, you can temporarily change the
IFS
environment variable. Here's how to do this in a bash script, assuming that as a field separator, only a newline is needed:
IFS=$'\n'
After adding this command to the bash script, it will work as it should, ignoring spaces and tabs, considering only newline characters as field separators.
#!/bin/bash file="/etc/passwd" IFS=$'\n' for var in $(cat $file) do echo " $var" done
If this script is run, it will output exactly what is required of it, giving, in each iteration of the loop, access to the next line written to the file.
Line by line crawling file contents in for loopOther characters can be delimiters. For example, above, we displayed the contents of the
/etc/passwd
. The user data in the rows is separated by colons. If you need to process such lines in a loop, the
IFS
can be configured as follows:
IFS=:
Traversing the files contained in the directory
One of the most common options for using
for
loops in bash scripts is to crawl files in a certain directory and to process these files.
For example, here’s how you can display a list of files and folders:
#!/bin/bash for file in /home/likegeeks/* do if [ -d "$file" ] then echo "$file is a directory" elif [ -f "$file" ] then echo "$file is a file" fi done
If you have dealt with the
previous material in this series of articles, you should understand the
if-then
construction device, as well as how to distinguish the file from the folder. If you find it difficult to understand the above code, reread this material.
This is what the script displays.
Displays the contents of the folderNotice how we initialize the loop, namely, the wildcard "*" at the end of the folder address. This symbol can be perceived as a pattern meaning: “all files with any names”. It allows you to organize automatic substitution of file names that match the pattern.
When checking a condition in an
if
, we enclose the variable name in quotes. This is done because the name of the file or folder may contain spaces.
C style for loops
If you are familiar with the C programming language, the syntax for describing bash
for
loops may seem strange to you, since you are obviously used to this description of loops:
for (i = 0; i < 10; i++) { printf("number is %d\n", i); }
In bash scripts, you can use
for
loops, the description of which looks very similar to the cycles in the C style, although without some differences this was not enough. The cycle diagram for a similar approach looks like this:
for (( ; ; ))
You can write this in bash like this:
for (( a = 1
And here is a working example:
#!/bin/bash for (( i=1; i <= 10; i++ )) do echo "number is $i" done
This code will list the numbers from 1 to 10.
Work cycle in style CWhile loop
The
for —
construct
for —
not the only way to organize loops in bash scripts. Here you can use
while
loops. In such a cycle, you can specify a command to check a certain condition and execute the body of the cycle until the condition being checked returns zero, or a signal to successfully complete a certain operation. When the loop condition returns a non-zero value, which means an error, the loop will stop.
Here is a diagram of the organization of cycles
while
while
do
done
while
while
do
done
Take a look at an example script with this cycle:
#!/bin/bash var1=5 while [ $var1 -gt 0 ] do echo $var1 var1=$[ $var1 - 1 ] done
At the entrance to the loop, it is checked whether the variable
$var1
greater than zero. If so, the body of the loop is executed, in which one is subtracted from the variable value. This happens in each iteration, and we output the value of the variable to the console before modifying it. As soon as
$var1
takes the value 0, the loop ends.
The result of the while loopIf you do not modify the
$var1
variable, this will cause the script to fall into an infinite loop.
Nested loops
In the body of the loop, you can use any command, including the start of other cycles. Such constructions are called nested loops:
#!/bin/bash for (( a = 1; a <= 3; a++ )) do echo "Start $a:" for (( b = 1; b <= 3; b++ )) do echo " Inner loop: $b" done done
Below is what this script displays. As you can see, the first iteration of the outer loop is first performed, then the three iterations of the inner loop, after its completion, the outer loop again enters, then again the inner loop.
Nested loopsFile content processing
Most often, nested loops are used to process files. Thus, the outer loop is engaged in searching the file lines, and the inner one is already working with each line. Here, for example, looks like the processing of the
/etc/passwd
:
#!/bin/bash IFS=$'\n' for entry in $(cat /etc/passwd) do echo "Values in $entry –" IFS=: for value in $entry do echo " $value" done done
In this script, two cycles. The first is traversed in rows, using the line feed as a separator. Internal is busy parsing lines whose fields are separated by colons.
File data processingThis approach can be used when processing CSV files, or any similar files, by writing, as necessary, the delimiter character to the
IFS
environment variable.
Cycle management
Perhaps, after entering the cycle, it will be necessary to stop it when the variable of the cycle reaches a certain value, which does not correspond to the initially specified condition of the end of the cycle. Will it be necessary in such a situation to wait for the normal completion of the cycle? No, of course, the following two commands will be useful in such cases:
Break command
This command allows you to interrupt the loop. It can be used for both
for
and for
while
loops:
#!/bin/bash for var1 in 1 2 3 4 5 6 7 8 9 10 do if [ $var1 -eq 5 ] then break fi echo "Number: $var1" done
Such a cycle, under normal conditions, will go through the entire list of values ​​from the list. However, in our case, its execution will be interrupted when the
$var1
variable is equal to 5.
Early exit from the for loopHere is the same thing, but for the
while
:
#!/bin/bash var1=1 while [ $var1 -lt 10 ] do if [ $var1 -eq 5 ] then break fi echo "Iteration: $var1" var1=$(( $var1 + 1 )) done
The
break
command, executed when the value of
$var1
becomes equal to 5, terminates the loop. The console displays the same as in the previous example.
Continue command
When this command is encountered in the loop body, the current iteration is completed ahead of schedule and the next one begins, and no exit from the loop occurs. Let's look at the
continue
command in the
for
loop:
#!/bin/bash for (( var1 = 1; var1 < 15; var1++ )) do if [ $var1 -gt 5 ] && [ $var1 -lt 10 ] then continue fi echo "Iteration number: $var1" done
When the condition inside the loop is satisfied, that is, when
$var1
greater than 5 and less than 10, the shell executes the
continue
command. This leads to the omission of the commands remaining in the cycle body and the transition to the next iteration.
The continue command in the for loopLoop processing
The data output in the cycle can be processed either by redirecting the output or by transferring it to the pipeline. This is done by adding output processing commands after the
done
instruction.
For example, instead of showing on the screen what is displayed in the loop, you can write it all into a file or transfer it somewhere else:
The shell will create the file
myfile.txt
and redirect output of the
for
construct to this file. Open the file and make sure that it contains exactly what is expected.
Redirect loop output to fileExample: search for executable files
Let's take advantage of what we have already disassembled and write something useful. For example, if you need to find out exactly which executable files are available in the system, you can scan all the folders recorded in the PATH environment variable. The whole arsenal of tools that we need for this, we already have, we just need to put it all together:
#!/bin/bash IFS=: for folder in $PATH do echo "$folder:" for file in $folder/* do if [ -x $file ] then echo " $file" fi done done
Such a script, small and simple, allowed us to get a list of executable files stored in folders from the
PATH
.
Search for executable files in folders from the PATH variableResults
Today we talked about
for
and
while
loops in bash scripts, how to run them, how to manage them. Now you know how to process rows with different delimiters in cycles, you know how to redirect data output in cycles to files, how to view and analyze the contents of directories.
If we assume that you are a developer of bash scripts, who know about them only what is stated in the
first part of this series of articles, and in this, the second, then you can already write something useful. Ahead - the third part, having dealt with that, you will learn how to pass parameters and command line keys to bash scripts, and what to do about it.
Dear readers! In the comments to the
previous material you told us a lot of interesting things. We are sure that all this will provide invaluable assistance to those who want to learn how to program for bash. But this topic is huge, so again we ask the experts to share the experience, and newcomers - impressions.
