While & for loops
While & for loops
The primary goal of a script is to avoid doing the same task twice. If you have to manually create a user on one server, it’s a relatively quick task. If you have to manually create that user on 1,000 servers, it becomes a gruelling process. Loops allow us to execute a block of code repeatedly without rewriting it.
There are two types of loop, for loops and while loops. A while loop is executed an undetermined number of times, as long as a condition is True. A for loop is executed a predetermined number of times, based on the number of items in a sequence.
We'll discuss both types of loops and their applications in this chapter.
While loops
Concept: while loop
A while loop requires a test expression that evaluates to True or False. While the test expression evaluates to True, the block of code beneath it is executed. When the test expression evaluates to False, the loop is exited, and the program continues executing the code that follows the loop.
Warning
It is extremely important to ensure that the test expression will eventually evaluate to False, otherwise the loop will never exit, and the program will run indefinitely.
while test_expression:
# This code runs only if test_expression is True
do_something()
# Update the test expression to eventually become False
test_expression = update_test_expression()Let's consider the case of a script that connects to an active directory server and lists all users that are currently logged in. In order to ensure that the script is robust and can deal with network issues, the script should wait for a successful connection to the server before attempting to list the users.
Since we have not yet discussed how to connect to a server, we will simulate the connection status with a variable called ad_service_up that is initially set to False.
ad_service_up = False
while not ad_service_up:
print("Trying to connect to Active Directory server...")
ad_service_up = True
print("Connected to Active Directory server.")
print("Retrieving active users...", end="\n\n")
border = '#' * 60
print(border)
print(f"{'Active users':^60}")
print(border)
print("""
Sebastiaan_H
Bart_T
Jochen_M
Maxim_C
""")Since the ad_service_up variable is initially set to False, the while loop will execute. Because the loop always sets the variable to True, the loop will execute exactly once. The output of the script will be:
Trying to connect to Active Directory server...
Connected to Active Directory server.
Retrieving active users...
############################################################
Active users
############################################################
Sebastiaan_H
Bart_T
Jochen_M
Maxim_CThe program is now predictable and the loop could be removed, but in a real-world scenario, the connection to the server may fail and the loop would continue until a successful connection is made. To illustrate this, we'll use the build-in modules to simulate a non-deterministic connection check.
Concept: Build-in modules
Python, like any other programming language, has a set of build-in modules that can be used to extend the functionality of the language beyond simple data types and control structures. The complete list of build-in modules can be found in the Python documentation.
In order to use a build-in module, it must first be imported into the script using the import statement. The code below imports the random module, which contains functions that can be used to generate random numbers and other random data.
import random
random_integer = random.randint(1, 10)
print(f"Random integer between 1 and 10: {random_integer}")The example above is perfectly valid. However, it is also possible to import only a specific function from a module using the from statement.
from random import randint
random_integer = randint(1, 10)
print(f"Random integer between 1 and 10: {random_integer}")While random can be used to generate a boolean, we'll instead opt to generate an integer between 0 and 3, and only consider the connection successful if the generated number is 0. This allows us to clearly illustrate that the while loop will continue to execute until a successful connection is made, no matter how long this takes.
We'll also use the time module to wait between connection attempts, otherwise we would be bombarding the server with connection requests and congesting the network.
import time
import random
ad_service_up = False
while not ad_service_up:
print("Trying to connect to Active Directory server...")
ad_service_up = random.randint(0,3) == 0
time.sleep(1)
print("Connected to Active Directory server.")
print("Retrieving active users...", end="\n\n")
time.sleep(1)
border = '#' * 60
print(border)
print(f"{'Active users':^60}")
print(border)
print("""
Sebastiaan_H
Bart_T
Jochen_M
Maxim_C
""")The output is now non-deterministic, and the number of connection attempts will vary each time the script is executed.
Trying to connect to Active Directory server...
Trying to connect to Active Directory server...
Connected to Active Directory server.
Retrieving active users...
############################################################
Active users
############################################################
Sebastiaan_H
Bart_T
Jochen_M
Maxim_CTrying to connect to Active Directory server...
Trying to connect to Active Directory server...
Trying to connect to Active Directory server...
Trying to connect to Active Directory server...
Trying to connect to Active Directory server...
Trying to connect to Active Directory server...
Trying to connect to Active Directory server...
Connected to Active Directory server.
Retrieving active users...
############################################################
Active users
############################################################
Sebastiaan_H
Bart_T
Jochen_M
Maxim_CPreventing infinite loops
The script will continue to attempt to connect to the server until a successful connection is made, while the script will very likely succeed in connecting to the server, it is possible that the connection will never be successful. To prevent the script from running indefinitely, we can add a counter to limit the number of connection attempts. If the connection is not successful after a certain number of attempts, the script will exit with an error.
Concept: Exit code
When a script is executed, it will return an exit code to the operating system when it finishes running. The exit code is a number that indicates whether the script ran successfully or encountered an error.
The exit code is typically 0 for a successful execution, and a non-zero value for an error.
In order to exit a script with a specific exit code, the exit function from the sys module must be used.
import sys
import random
if random.randint(0,1) == 0:
print("Script ran successfully.")
sys.exit(0)
else:
print("Script encountered an error.")
sys.exit(1)An error code must be a positive integer no larger than 255. There are a few reserved exit code which should not be used outside their intended purpose. Any other code can be used to indicate an application specific error.
| Exit code | Meaning |
|---|---|
| 0 | Success |
| 1 | General error |
| 2 | Misuse of shell builtins |
| 126 | Command invoked cannot execute |
| 127 | Command not found |
| 128 | Invalid argument to exit |
| 130 | Script terminated by Control-C |
import time
import random
import sys
ad_service_up = False
attempt_count = 0
while not ad_service_up and attempt_count < 3:
print("Trying to connect to Active Directory server...")
ad_service_up = random.randint(0,3) == 0
time.sleep(1)
attempt_count += 1
if attempt_count == 3:
print("Could not connect to Active Directory server", file=sys.stderr)
sys.exit(10)
print("Connected to Active Directory server.")
print("Retrieving active users...", end="\n\n")
time.sleep(1)
border = '#' * 60
print(border)
print(f"{'Active users':^60}")
print(border)
print("""
Sebastiaan_H
Bart_T
Jochen_M
Maxim_C
""")Note that line 18 uses the file argument of the print function to print the error message to the standard error stream instead of the standard output stream. This allows the error message to be redirected to a log file or other output stream, as discussed in the Linux course.

For loops
Concept: for loop
A for loop is executed a predetermined number of times, based on the number of items in a sequence (a list of users, a string, or a range of numbers). A for loop is the best choice when the number of iterations is known in advance. Every loop can be expressed as a while loop, but a for loop is more concise and easier to read.
Let's say that we need to write a script that creates a number of test users in a test environment. In that case, the script could request the number to create from the user, and then create that number of users with a for loop.[1]
Concept: range()
The range function is a built-in Python function that generates a sequence of numbers. It is commonly used in for loops to iterate over a specific range of values. The range() function can take one, two, or three arguments:
When called with a single argument, it generates numbers from up to (but not including) the specified value.
for i in range(5):
print(i, end=" ")
# Output: 0 1 2 3 4When called with two arguments, it generates numbers from the first argument up to (but not including) the second argument.
for i in range(1, 5):
print(i, end=" ")
# Output: 1 2 3 4When called with three arguments, it generates numbers from the first argument up to (but not including) the second argument, incrementing by the third argument.
for i in range(1, 5, 2):
print(i, end=" ")
# Output: 1 3While the examples above used positive argmument, the range() function can also accept negative arguments, allowing for reverse iteration.
for i in range(5, 0, -1):
print(i, end=" ")
# Output: 5 4 3 2 1Using the range function, we can create a for loop that will iterate a specified number of times, creating a new user on each iteration.
number_of_users = int(input("How many users would you like to create? : "))
for i in range(0, number_of_users):
print(f"Creating user {i}")The script could produce the following output:
How many users would you like to create? : 5
Creating user 0
Creating user 1
Creating user 2
Creating user 3
Creating user 4In a real-world scenario, the script would likely require the number of users to be passed as a command-line argument. Since this hasn't yet been covered, we'll use the input function to request the number of users to create. In the last chapter, we will discuss how to use command-line arguments to pass parameters to a script. ↩︎