Bash While Loop
The short answer
In Bash, the [.inline-code]while[.inline-code] statement is a control structure used to repeat a set of instructions for as long as a specified condition remains [.inline-code]true[.inline-code].
To declare a [.inline-code]while[.inline-code] loop, you can use the following syntax:
Where:
- [.inline-code]condition[.inline-code] is an expression used to keep the loop running for as long as it evaluates to [.inline-code]true[.inline-code].
- [.inline-code]do[.inline-code] and [.inline-code]done[.inline-code] are used to delimit the instructions executed by the [.inline-code]while[.inline-code] loop.
- [.inline-code]instructions[.inline-code] is a list of one or more commands that will be executed by the [.inline-code]while[.inline-code] loop.
For example, let's consider this script used to print every digit from [.inline-code]1[.inline-code] to [.inline-code]9[.inline-code]:
Where:
- [.inline-code]$x -le 9[.inline-code] is used to evaluate whether the [.inline-code]x[.inline-code] variable is lesser than or equal to [.inline-code]9[.inline-code].
- [.inline-code]echo $x[.inline-code] is used to output the value of the [.inline-code]x[.inline-code] variable.
- [.inline-code](( x++ ))[.inline-code] is used to increment the value of the x variable by 1 at each loop iteration.
[#terminate-the-loop-with-break] Terminating the loop with the break
statement [#terminate-the-loop-with-break]
The [.inline-code]break[.inline-code] statement is used to immediately terminate the current loop, regardless of whether the loop's condition evaluates or not to [.inline-code]false[.inline-code].
For example, let's consider this script that determines whether a number is prime:
Where:
- [.inline-code]$i -lt $number[.inline-code] checks whether the [.inline-code]i[.inline-code] variable is lesser than the [.inline-code]number[.inline-code] variable.
- [.inline-code]$number -le 1[.inline-code] checks whether the [.inline-code]number[.inline-code] variable is lesser than or equal to [.inline-code]1[.inline-code].
- [.inline-code]$(($number % $i)) -eq 0[.inline-code] checks whether the [.inline-code]number[.inline-code] variable is divisible by the [.inline-code]i[.inline-code] variable.
- [.inline-code]break[.inline-code] immediately terminates the [.inline-code]while[.inline-code] loop if either one of the conditions above are true.
[#skip-iterations-with-continue] Skipping a loop iteration with the continue
statement [#skip-iterations-with-continue]
The [.inline-code]continue[.inline-code] statement is used to skip the current iteration of a loop and directly proceed to the next iteration, without executing the remaining instructions.
For example, let's consider this script that prints all the numbers between [.inline-code]1[.inline-code] and [.inline-code]15[.inline-code] that are divisible by [.inline-code]3[.inline-code]:
Where:
- [.inline-code]$number -le $max[.inline-code] checks if the [.inline-code]number[.inline-code] variable is lesser than or equal to the [.inline-code]max[.inline-code] variable.
- [.inline-code]$((number % 3)) -ne 0[.inline-code] checks if the [.inline-code]number[.inline-code] variable is divisible by [.inline-code]3[.inline-code].
- [.inline-code]((number++))[.inline-code] increments the [.inline-code]number[.inline-code] variable by [.inline-code]1[.inline-code].
- [.inline-code]continue[.inline-code] skips the remaining instructions and immediately starts a new loop iteration from the beginning.
[#read-from-a-file] Reading from a file line by line [#read-from-a-file]
To read and process a text file line by line, you can combine the [.inline-code]while[.inline-code] loop with the [.inline-code]read[.inline-code] command as follows:
Where:
- The [.inline-code]file[.inline-code] variable is used to store the absolute or relative path to the file.
- The [.inline-code]read -r[.inline-code] command is used to read the file line by line.
- The [.inline-code]line[.inline-code] variable is used to store the current line returned by the [.inline-code]read[.inline-code] command.
- The [.inline-code]<[.inline-code] operator is used to specify the source the [.inline-code]read[.inline-code] command should read its input from.
For example, this script reads each line of the [.inline-code]"/var/log/apache2/access.log"[.inline-code] file and only output the lines that contain the [.inline-code]192.168.2.101[.inline-code] IP address:
[#read-from-the-standard-input] Reading from the standard input [#read-from-the-standard-input]
To read and process text from the standard input, you can combine the [.inline-code]while[.inline-code] loop with the [.inline-code]read[.inline-code] command as follows:
Where:
- [.inline-code]input[.inline-code] is a variable that stores the input captured by the [.inline-code]read[.inline-code] command.
For example, let's consider this script that makes a player enter a number and a second player guess that number:
Where:
- [.inline-code]read -p[.inline-code] prompts the user with a string and reads its input.
- [.inline-code]sleep[.inline-code] pauses the execution of the program for a certain amount of seconds.
- [.inline-code]clear[.inline-code] clears all the text from the terminal window.
[#read-from-arrays] Iterating on array elements [#read-from-arrays]
To iterate over the elements of an array, you can initialize an index variable to zero and use the loop condition to check if the index is less than the array's length, incrementing the index within the loop to access and process each element sequentially.
Where:
- [.inline-code]element1, …, elementN[.inline-code] are a list of comma-separated array values, such as strings or numbers.
- [.inline-code]index[.inline-code] is a positional index used to access the current array element.
- [.inline-code]${#array[@]}[.inline-code] is used to get the number of elements (i.e. the length) of the array.
- [.inline-code]${array[$index]}[.inline-code] is used to access the value specified at [.inline-code]index[.inline-code].
- [.inline-code]((index++))[.inline-code] is used to increment the index value by one.
For example, let's consider this script that outputs all the files in the current directory with a [.inline-code].js[.inline-code] file extension:
Where:
- [.inline-code]($(ls))[.inline-code] is used to declare the list of files returned by the [.inline-code]ls[.inline-code] command as an array of strings.
- [.inline-code]${files[$index]} =~ .js$[.inline-code] checks if the current filename ends with the string [.inline-code]".js"[.inline-code].
[#create-an-infinite-loop] Creating an infinite while
loop [#create-an-infinite-loop]
To create an infinite while loop in Bash, you must define a condition that never evaluates to [.inline-code]false[.inline-code].
The most common way of doing so is to use the built-in [.inline-code]true[.inline-code] value as follows:
Alternatively, you can also use a semicolon character ([.inline-code]:[.inline-code]) as follows:
For example, let's consider this script that simply "echoes" back into the terminal the user input until it reads the [.inline-code]"exit"[.inline-code] string: