Controlling Program Flow

Learn how to alter the flow of your Perl code using decisions and loops. This essential tutorial covers statements such as if, while, until, do, for and foreach.

Normally when you run a Perl script, the computer moves through each line of your script in turn, executing each line as it goes. However, often you'll want to alter this flow through the script.

For example, you might want to run different pieces of code depending on whether a visitor has filled out a form correctly or not. Also, you often want to run the same piece of code lots of times - for example, when reading through each line of a file.

Perl features a number of useful ways to alter the path of execution through your script. In this tutorial we'll show you the most common techniques, and how you can use them.

Making decisions: the if statement

The if statement tells Perl to choose whether to run a particular piece of code or not depending on a certain condition (or set of conditions).

For example, the following code will display the message "x is less than 10" if the value of the variable $x is less than 10. (If it's 10 or greater, the code within the braces ({ }) will be skipped.)


if ( $x < 10 )
{
  print "x is less than 10";
}

You can use the else statement to run a different block of code if the condition in the if statement is not met. For example:


if ( $x < 10 )
{
  print "x is less than 10";
}
else
{
  print "x is 10 or greater";
}

If the condition $x < 10 fails, control passes to the block of code after the else statement.

You can take the else concept one stage further with the elsif statement. elsif is short for "else if", and allows you to check as many conditions as you like. For example:


if ( $x < 10 )
{
  print "x is less than 10";
}
elsif ( $x < 100 )
{
  print "x is between 10 and 99";
}

This will return an appropriate message depending on whether the variable $x is less than 10, or between 10 and 99.

You've probably already spotted that this code will do nothing if $x is greater than or equal to 100! To fix this, we can modify the code as follows:


if ( $x < 10 )
{
  print "x is less than 10";
}
elsif ( $x < 100 )
{
  print "x is between 10 and 99";
}
else
{
  print "x is 100 or greater";
}

You can chain as many elsifs together as you like, optionally followed by an else at the end of the chain, as shown above.

The unless statement

The unless statement is simply the opposite of the if statement. In other words, it is saying "unless this condition is true, run this block of code". For example:


unless ( $x >= 10 )
{
  print "x is less than 10";
}

Shorthand for if and unless

If you only want to run one line of code depending on the outcome of the if/unless condition, you can write code like this:


print "x is less than 10" if ( $x < 10 );

Or, with the unless statement:


print "x is less than 10" unless ( $x >= 10 );

Looping with the while statement

The while statement is one of the looping statements available in Perl. A while loop allows you to keep executing a piece of code over and over again, as long as a certain condition is still met.

A while loop looks like this:


while ( condition )
{
  (stuff to do inside the loop)
}

As long as condition remains true, the code inside the loop will execute. After the code has executed once, the condition is tested again, and so on.

For example, this code will count up from 1 to 3 using the variable $counter. Each time through the loop, $counter is incremented by 1 (with the code $counter++).

The code in the loop will only run as long as $counter is less than or equal to 3. Once $counter reaches 4, the loop will exit.


$counter = 1;

while ( $counter <= 3 )
{
  print ( "I've counted to: $counter\n" );
  $counter++;
}

This will output the following:


I've counted to: 1
I've counted to: 2
I've counted to: 3

Looping with the until statement

As with if and unless, until is basically the opposite of the while statement. So the above loop could be rewritten to use until as follows:


$counter = 1;

until ( $counter > 3 )
{
  print ( "I've counted to: $counter\n" );
  $counter++;
}

The do statement and loops

With while and until loops, it's possible to check the condition after the block of code inside the loop has been executed, rather than before it. You can do this using the do statement, as follows:


do
{
  (stuff to do inside the loop)
} while ( condition );

do
{
  (stuff to do inside the loop)
} until ( condition );

So we could rewrite our while counting example above as follows:


$counter = 1;

do
{
  print ( "I've counted to: $counter\n" );
  $counter++;
} while ( $counter <= 3 );

Because the condition is checked after the code block has run, the code block always runs at least once. This can be very handy if, for example, the variable you are testing in the condition needs to be initialised inside the code block!

Compare with the standard while and until loops above, where the condition is tested before the code block is run. If the condition is false, the code block will never be run.

Looping with the for statement

The for statement is another way to build loops in Perl. You can think of it as a more specialised, shorthand version of the while loop.

The for loop allows you to specify the initial value of a looping variable (e.g. $i), then a condition test, and finally a statement to update the loop variable, all in one statement!

This means that you can write loops that involve a counter much more easily and neatly than using a while loop. In fact the examples above that use the while statement could be more succinctly written as a for loop.

Here's an example that counts from 1 to 10, placing the numbers in a string as it goes (using the string concatenation operator, '.'). It then outputs the final string.


$output_string = "";

for ( $i=1; $i<=10; $i++ )
{
  $output_string .= "I've counted to: $i\n";

}

print $output_string;

Looping with the foreach statement

foreach gives you a quick and easy way to loop over a list of values. The general structure of a foreach loop is:


foreach variable ( list )
{
  ( do stuff )
}

As each element of the list variable list is processed, it is made available via the variable variable to the code block inside the loop, allowing you to manipulate that list element.

For example, here is a simple piece of Perl code that counts up to ten in words:


# Build a list variable to store the words
@word_list = ( 'one', 'two', 'three', 'four', 'five', 'six',
  'seven', 'eight', 'nine', 'ten' );

# Loop through the list, displaying each list item in turn
foreach $count_word ( @word_list )
{
  print "I've counted to: $count_word\n";
}

Each time through the loop, the next list element ("one", "two", etc) is made available via the variable $count_word, which we can then use inside the loop to display the output.

This script displays the following output when run:


I've counted to: one
I've counted to: two
I've counted to: three
I've counted to: four
I've counted to: five
I've counted to: six
I've counted to: seven
I've counted to: eight
I've counted to: nine
I've counted to: ten

Controlling loops: the next, last and redo statements

Sometimes it's useful to be able to alter the normal flow of a loop. You can do this in Perl with the following statements:

  • last breaks out of the current loop entirely, continuing execution with the first statement outside the loop block.

  • next skips the rest of the code block after the next statement, and starts the next iteration of the loop (or ends the loop if the loop condition is now false).

  • redo skips the rest of the code block after the redo statement, and starts executing the loop block from the top again, but without re-testing the loop condition.

Here's an example that uses the last statement to only count up to 5, even though the loop would normally count to 10:


$output_string = "";

for ( $i=1; $i<=10; $i++ )
{
  $output_string .= "I've counted to: $i\n";
  last if ( $i == 5 );
}

print $output_string;

This example uses the next statement to count to 10, missing out the number 5:


$output_string = "";

for ( $i=1; $i<=10; $i++ )
{
  next if ( $i == 5 );
  $output_string .= "I've counted to: $i\n";
}

print $output_string;

Nested loops and labels

Often you want to run one loop inside another loop. This is known as loop nesting. Nesting is handy for looping through two lists where the second list should be looped through for each element in the first list. For example, the following code lists the abilities of 5 children (reading, walking and talking) by looping through all 3 abilities for each child:


# Build a list variable to store the children's names
@children = ( 'Anna', 'Bert', 'Charlie', 'David', 'Fiona' );

# Build a list variable to store the abilities
@abilities = ( 'read', 'walk', 'talk' );

# Display the abilities for each child

foreach $child ( @children )
{
  foreach $ability ( @abilities )
  {
    print "$child can $ability\n";
  }
}

This script prints the following:


Anna can read
Anna can walk
Anna can talk
Bert can read
Bert can walk
Bert can talk
Charlie can read
Charlie can walk
Charlie can talk
David can read
David can walk
David can talk
Fiona can read
Fiona can walk
Fiona can talk

However, what if Bert can't walk yet and David can't talk? We can use the next statement along with a loop label to skip these two cases:


# Build a list variable to store the children's names
@children = ( 'Anna', 'Bert', 'Charlie', 'David', 'Fiona' );

# Build a list variable to store the abilities
@abilities = ( 'read', 'walk', 'talk' );

# Display the abilities for each child

foreach $child ( @children )
{
  ABILITY: foreach $ability ( @abilities )
  {
    next ABILITY if ( $child eq "Bert" && $ability eq "walk" );
    next ABILITY if ( $child eq "David" && $ability eq "talk" );
    print "$child can $ability\n";
  }
}

The ABILITY: text placed before the inner foreach loop assigns the label "ABILITY" to this loop. We then place the label after the next statements in the loop block to tell Perl that we want to skip straight to the next iteration of the "ABILITY" loop (missing out the print statement).

In fact, if we missed off the ABILITY after the next statements, the script would still work because Perl assumes you mean the innermost loop that encloses the next statements if you don't specify otherwise. However, what if Charlie couldn't read, walk or talk yet? We could skip Charlie out altogether by using next on the outer loop, as follows:


# Build a list variable to store the children's names
@children = ( 'Anna', 'Bert', 'Charlie', 'David', 'Fiona' );

# Build a list variable to store the abilities
@abilities = ( 'read', 'walk', 'talk' );

# Display the abilities for each child

CHILD: foreach $child ( @children )
{
  ABILITY: foreach $ability ( @abilities )
  {
    next ABILITY if ( $child eq "Bert" && $ability eq "walk" );
    next ABILITY if ( $child eq "David" && $ability eq "talk" );
    next CHILD if ( $child eq "Charlie" );
    print "$child can $ability\n";
  }
}

With this script, we tell Perl to miss out Charlie altogether with next CHILD if ( $child eq "Charlie" ). Here's the output from our script:


Anna can read
Anna can walk
Anna can talk
Bert can read
Bert can talk
David can read
David can walk
Fiona can read
Fiona can walk
Fiona can talk

Happy looping! :)

Follow Elated

Related articles

Responses to this article

There are no responses yet.

Post a response

Want to add a comment, or ask a question about this article? Post a response.

To post responses you need to be a member. Not a member yet? Signing up is free, easy and only takes a minute. Sign up now.

Top of Page