Beginning Perl Lesson 3

Table of Contents

Perl scalar variables

Perl has three major variable types (scalar, array, and hash). A scalar variable holds exactly one item. (The array and hash variable types, as we’ll see later, can hold more than one item).

Think of a scalar variable as a container that holds a value. The useful thing about a scalar variable is that it will hold just about anything, so long as there is only one item to hold. A scalar variable can hold a number, including integers (e.g., 42, -3) and floating point numbers (e.g., 3.14159, 6.02e23). And a scalar can hold a string of characters (e.g., "Perl" or "Perl is a programming language that was invented by Larry Wall").

A scalar can also hold nothing, which means that its value is undefined. If you create a variable but don’t initialize it by putting something in it, then the variable exists, but its value is undefined.

A scalar variable always begins with a $ symbol. In our scripts, we’ll create scalar variables using the my() function. Here’s how we do it:

    my( $name );
    my( $address );

This creates two scalar variables for us, $userName and $password. Until we assign a value to each variable, the value of that variable is undefined. (We have created the container, but there’s nothing inside yet.)

When we create variables, we will give them names that make it clear what kind of value they will hold. We would expect that the variable $name would contain a person’s name and that the variable $address would contain a person’s address. We could have used shorter names, such as $n instead of $name, and $a instead of $address, but such names are so short that later on we might not remember what these variables are used for.

Here’s a simple script that creates and initializes some variables, then prints their values to the screen.

#!/usr/bin/perl
#
#   scalars1.pl
#   13-Jun-2004
#
#   Conrad Halling
#   conrad.halling@sphaerula.com
#
#   This script demonstrates how to create and use scalar variables.

    my( $cat1 );
    my( $cat2 );
    my( $dog1 );
    my( $dog2 );

    $cat1 = "Snowball";
    $cat2 = "Fluffy";

    print( "The names of my cats are $cat1 and $cat2.\n" );

    $dog1 = "Bowser";
    $dog2 = "Fido";

    print( "The names of my dogs are $dog1 and $dog2.\n" );

    #   Variables can be created anywhere in a script.

    my( $bird1 );
    my( $bird2 );

    #   Notice that I don't initialize $bird2. What happens when I try to use it?

    $bird1 = "Fred";

    print( "The names of my birds are $bird1 and $bird2.\n" );

When we run this script with the command

> perl scalars1.pl

we get the following output:

The names of my cats are Snowball and Fluffy.
The names of my dogs are Bowser and Fido.
The names of my birds are Fred and .

You can see that when we used the variable $bird2, nothing printed. That’s because the value of $bird2 was not defined.

The pragma use warnings;

In the script above, I didn’t initialize the variable $bird2, so when I tried to use it in a print statement, nothing appeared. This is undesirable behavior, or a bug. How can I get Perl to warn me about this problem?

In Perl 5.6.0 and later, we can put the statement

use warnings;

at the top of the script. When we do this, Perl will warn us when we attempt to use an undefined variable. You should always put this statement at the beginning of every script, and we’ll do that from now on. (If you’re using a version of Perl earlier than 5.6.0, you can’t use use warnings;; instead, you put a -w after the shebang line, like this:

#!/usr/bin/perl -w

You’ll see this in older scripts and older Perl books. From now on, we’ll assume that you’re using Perl 5.6.0 or later (at the time of writing, the version of Perl is 5.8.7).

The use warnings; statement is a pragma; using a pragma changes the behavior of Perl.

Our revised script now looks like this (where the change is highlighted in bold):

#!/usr/bin/perl
#
#   scalars2.pl
#   13-Jun-2004
#
#   Conrad Halling
#   conrad.halling@sphaerula.com
#
#   This script demonstrates how to create and use scalar variables.

use warnings;

    my( $cat1 );
    my( $cat2 );
    my( $dog1 );
    my( $dog2 );

    $cat1 = "Snowball";
    $cat2 = "Fluffy";

    print( "The names of my cats are $cat1 and $cat2.\n" );

    $dog1 = "Bowser";
    $dog2 = "Fido";

    print( "The names of my dogs are $dog1 and $dog2.\n" );

    #   Variables can be created anywhere in a script.

    my( $bird1 );
    my( $bird2 );

    #   Notice that I don't initialize $bird2. What happens when I try to use it?

    $bird1 = "Fred";

    print( "The names of my birds are $bird1 and $bird2.\n" );

Now Perl warns me when I use an uninitialized value, and the output now looks like:

> perl scalars2.pl
The names of my cats are Snowball and Fluffy.
The names of my dogs are Bowser and Fido.
Use of uninitialized value in concatenation (.) or string at scalars2.pl line 37.
The names of my birds are Fred and .

The line in bold above is the warning that Perl gives us when we use a variable whose value is undefined.

A warning is all very fine, but what we’d like to do in some circumstances is check to see if a variable is defined before we use it. Perl lets us do this with the defined() function. We’ll discuss this below.

Getting user input using <>

Sometimes you need to ask the user a question, then proceed based on the answer.

You get input from the user using paired angle brackets (<>), which are called the line input operator (also known as the angle operator or diamond operator. You assign the result to a variable, as in this code snippet:

    print( "What is your name?\n" );
    $name = <>;
    print( "Your name is $name" );

Here’s a script that asks the user’s name and prints it out:

#!/usr/bin/perl
#
#   askName1.pl
#   13-Jun-2004
#
#   Conrad Halling
#   conrad.halling@sphaerula.com
#
#   This script asks the user her name, prints out the name, and quits.

use warnings;

    my( $name );

    print( "Hi. What is your name?\n" );
    $name = <>;
    print( "You replied that your name is $name.\n" );

Using chomp() to remove newline characters

Unfortunately, when you ask the user to enter something, Perl captures the newline character that results from the user pressing the enter key. This can make your output look bad when you use the result. If you run the askName1.pl script given above, here’s what the results look like on the computer screen:

> perl askName1.pl
Hi. What is your name?
Cynthia
You replied that your name is Cynthia
.

Note that the period at the end of the sentence ended up by itself on the line after the name. What happened was that when Perl got the input from the user, it captured "Cynthia\n" in $name. When Perl printed $name, it printed the newline character at the end of it, and that caused the period to end up on the next line.

To make it easy to fix this problem, Perl provides a function called chomp(). chomp() looks at a scalar variable to see if it is a string with a newline character at the end. If it is, chomp() removes the newline character from the end of the string. If the last character is not a newline character, then chomp() does nothing.

So we can fix our script as follows:

#!/usr/bin/perl
#
#   askName2.pl
#   13-Jun-2004
#
#   Conrad Halling
#   conrad.halling@sphaerula.com
#
#   This script asks the user her name, prints out the name, and quits.

use warnings;

    my( $name );

    print( "Hi. What is your name?\n" );
    $name = <>;
    chomp( $name );
    print( "You replied that your name is $name.\n" );

Now we see the correct results on the computer screen:

> perl askName2.pl
Hi. What is your name?
Cynthia
You replied that your name is Cynthia.

Branching with if, elsif, and else

When we’re scripting, we often want the script to branch, which means we want it to execute different branches, or parts, of the script depending on a decision that is made by the script.

The most fundamental way to make a choice is to use if and else. Here’s an example:

#!/usr/bin/perl
#
#   investor1.pl
#   13-Jun-2004
#
#   Conrad Halling
#   conrad.halling@sphaerula.com
#
#   This script asks a question that gives two choices. What happens afterwards
#   depends on the choice that the user made.

use warnings;

    my( $choice );

    print( "Hello, investor!\n" );
    print( "If you are a conservative investor, please enter 1.\n" );
    print( "If you are an aggressive investor, please enter 2.\n" );
    $choice = <>;
    chomp( $choice );

    if ( $choice == 1 )
    {
        print( "You are a conservative investor. I recommend treasury bonds.\n" );
    }
    else
    {
        print( "You are an aggressive investor. I recommend Internet stocks.\n" );
    }

Depending on the user’s response, the output will look like this:

Hello, investor!
If you are a conservative investor, please enter 1.
If you are an aggressive investor, please enter 2.
1
You are a conservative investor. I recommend treasury bonds.

or this:

Hello, investor!
If you are a conservative investor, please enter 1.
If you are an aggressive investor, please enter 2.
2
You are an aggressive investor. I recommend Internet stocks.

We have several new things to note here:

I was careless in this script. I tested for the number 1, but I didn’t test for the number 2. So if the user had entered 3 instead of 1 or 2, the script would do the wrong thing, and this is the bug. Here’s what the output looks like when the user enters 3 instead of 1 or 2:

Hello, investor!
If you are a conservative investor, please enter 1.
If you are an aggressive investor, please enter 2.
3
You are an aggressive investor. I recommend Internet stocks.

A good script always checks for invalid responses. Let’s improve this script by using elsif to test explicitly for a response of 2, then handle an invalid response in the final else clause.

#!/usr/bin/perl
#
#   investor2.pl
#   13-Jun-2004
#
#   Conrad Halling
#   conrad.halling@sphaerula.com
#
#   This script asks a question that gives two choices. What happens afterwards
#   depends on the choice that the user made.

use warnings;

    my( $choice );

    print( "Hello, investor!\n" );
    print( "If you are a conservative investor, please enter 1.\n" );
    print( "If you are an aggressive investor, please enter 2.\n" );
    $choice = <>;
    chomp( $choice );

    if ( $choice == 1 )
    {
        print( "You are a conservative investor. I recommend treasury bonds.\n" );
    }
    elsif ( $choice == 2 )
    {
        print( "You are an aggressive investor. I recommend Internet stocks.\n" );
    }
    else
    {
        print( "$choice is an invalid response.\n" );
    }

Now when the user enters an incorrect choice, the script recognizes this and responds appropriately.

Hello, investor!
If you are a conservative investor, please enter 1.
If you are an aggressive investor, please enter 2.
3
3 is an invalid response.

Using if and else, our script can make a two-way choice. Using if, elsif, and else, our script can make a three-way choice. In fact, you can use a potentially unlimited number of elsif clauses to make an infinite number of choices. Here’s an example:

#!/usr/bin/perl
#
#   investor3.pl
#   13-Jun-2004
#
#   Conrad Halling
#   conrad.halling@sphaerula.com
#
#   This script asks a question that gives four choices. What happens afterwards
#   depends on the choice that the user made.

use warnings;

    my( $choice );

    print( "Hello, investor!\n" );
    print( "If you are a very conservative investor, enter 1.\n" );
    print( "If you are a somewhat conservative investor, enter 2.\n" );
    print( "If you are a moderate investor, enter 3.\n" );
    print( "If you are an aggressive investor, enter 4.\n" );
    $choice = <>;
    chomp( $choice );

    if ( $choice == 1 )
    {
        print( "You are a very conservative investor.\n" );
        print( "I recommend treasury bonds.\n" );
    }

    elsif ( $choice == 2 )
    {
        print( "You are a somewhat conservative investor.\n" );
        print( "I recommend a balanced mutual fund.\n" );
    }

    elsif ( $choice == 3 )
    {
        print( "You are a moderative investor.\n" );
        print( "I recommend a stock index mutual fund.\n" );
    }

    elsif ( $choice == 4 )
    {
        print( "You are an aggressive investor.\n" );
        print( "I recommend Internet stocks.\n" );
    }

    else
    {
        print( "$choice is an invalid response.\n" );
    }

Operators for testing values

When we use if, we test the value of a variable against something. The sorts of tests are what we would expect: equals, not equals, less than, greater than, and so on.

Perl provides one set of operators for comparing numbers, another set for comparing strings:

Comparison Operators
Meaning Number String
equal to == eq
not equal to != ne
greater than > gt
greater than or equal to >= ge
less than < lt
less than or equal to <= le

Some Perl functions also return the result of a test. An example is the defined() function, which we mentioned above. The defined() function tells whether the value of a variable is defined or not. Here’s a code snippet that shows how to use it:

my( $var1 );

if ( defined( $var1 ) )
{
    print( "The value of var1 is $var1.\n" );
}
else
{
    print( "The value of var1 is not defined.\n" );
}

There is a bug in the investor3.pl script. Clearly, the script expects the user to enter numeric values. But what if the user enters a letter? Here’s what the output looks like.

> perl investor3.pl
Hello, investor!
If you are a very conservative investor, enter 1.
If you are a somewhat conservative investor, enter 2.
If you are a moderate investor, enter 3.
If you are an aggressive investor, enter 4.
x
Argument "x" isn't numeric in numeric eq (==) at investor3.pl line 21, <> line 1.
x is an invalid response.

Note that Perl generates a warning if the user enters a nonnumerical response. (We wouldn’t have been given this warning if we hadn’t added use warnings; at the top of the script.) Perl is warning us that we used the == operator, which checks for numeric equality, to test the response, which was nonnumeric.

When the user enters a nonnumeric response, then the == operator is not the correct operator to check for equality. If we look at the table of operators for testing values above, we see that we could use the eq operator, which compares strings. Since Perl considers 1 and 2 as either numeric values or as strings, depending on context, the eq operator is more appropriate here for testing equality.

We correct the script as given below, where the replacement of == by eq is shown in bold. We also put the numbers we’re comparing to inside quotation marks to emphasize that we’re performing a string comparison, not a number comparison.

#!/usr/bin/perl
#
#   investor4.pl
#   13-Jun-2004
#
#   Conrad Halling
#   conrad.halling@sphaerula.com
#
#   This script asks a question that gives four choices. What happens afterwards
#   depends on the choice that the user made.

use warnings;

    my( $choice );

    print( "Hello, investor!\n" );
    print( "If you are a very conservative investor, enter 1.\n" );
    print( "If you are a somewhat conservative investor, enter 2.\n" );
    print( "If you are a moderate investor, enter 3.\n" );
    print( "If you are an aggressive investor, enter 4.\n" );
    $choice = <>;
    chomp( $choice );

    if ( $choice eq "1" )
    {
        print( "You are a very conservative investor.\n" );
        print( "I recommend treasury bonds.\n" );
    }

    elsif ( $choice eq "2" )
    {
        print( "You are a somewhat conservative investor.\n" );
        print( "I recommend a balanced mutual fund.\n" );
    }

    elsif ( $choice eq "3" )
    {
        print( "You are a moderative investor.\n" );
        print( "I recommend a stock index mutual fund.\n" );
    }

    elsif ( $choice eq "4" )
    {
        print( "You are an aggressive investor.\n" );
        print( "I recommend Internet stocks.\n" );
    }

    else
    {
        print( "$choice is an invalid response.\n" );
    }

Now if the user enters a nonnumeric value as a response, the output no longer contains a warning.

> perl investor4.pl
Hello, investor!
If you are a very conservative investor, enter 1.
If you are a somewhat conservative investor, enter 2.
If you are a moderate investor, enter 3.
If you are an aggressive investor, enter 4.
x
x is an invalid response.

Homework assignment

Write a script that asks a person’s name and a few other simple questions. One of the questions should provide multiple choices. Store the answers in variables. Then print the answers out.

Use if, elsif, and else to provide a response that is unique to each choice for the multiple choice question.

The results should look something like this, where what the computer prints on the screen is in bold type and what the user types is in medium type:

> perl interview1.pl

Welcome to our interview!

What is your name?

Georgia

Hi, Georgia. What is your favorite programming language?

perl

M&Ms come in six colors: red, orange, yellow, green, blue, and brown.
Which color of M&Ms is your favorite?

red

Your preference for red indicates that
you're destined to be quite wealthy.

Thanks, Georgia. It was most interesting to learn that your
favorite programming language is perl and that
your favorite color of M&Ms is red.

Good-bye!

>

Here is the script that produces this interview. Note that in this script, we are comparing a variable that contains a string against a set of string values, so we have to use eq, the string equal to operator.

#!/usr/bin/perl
#
#   interview1.pl
#   13-Jun-2004
#
#   Conrad Halling
#   conrad.halling@sphaerula.com
#
#   This is a demonstration script that demonstrates the following Perl concepts:
#       printing strings
#       printing strings containing variables
#       getting input from the user
#       using if, elsif, and else for branching
#       using the eq operator to compare two strings

use warnings;

    my( $color );
    my( $programmingLang );
    my( $userName );

    #   Get the user's name.

    print( "\n" );
    print( "Welcome to our interview!\n\n" );
    print( "What is your name?\n\n" );
    $userName = <>;
    chomp( $userName );

    #   Use the user's name in the next question.
    #   Get the user's favorite programming language.

    print( "\n" );
    print( "Hi, $userName. What is your favorite programming language?\n\n" );
    $programmingLang = <>;
    chomp( $programmingLang );

    #   Give the user a set of choices and ask for one.

    print( "\n" );
    print( "M&Ms come in six colors: red, orange, yellow, green, ",
        "blue, and brown.\n" );
    print( "Which color of M&Ms is your favorite?\n\n" );
    $color = <>;
    chomp( $color );
    print( "\n" );

    #   Use if elsif else to test the various possibilities for $color.

    print( "Your preference for $color indicates that\n" );

    if ( $color eq "red" )
    {
        print( "you're destined to be quite wealthy.\n" );
    }

    elsif ( $color eq "orange" )
    {
        print( "you're kind and sympathetic.\n" );
    }

    elsif ( $color eq "yellow" )
    {
        print( "you're bold and courageous.\n" );
    }

    elsif ( $color eq "green" )
    {
        print( "you're popular with your colleagues.\n" );
    }

    elsif ( $color eq "blue" )
    {
        print( "you're thoughtful and courteous.\n" );
    }

    elsif ( $color eq "brown" )
    {
        print( "you're very intelligent.\n" );
    }

    else
    {
        print( "you didn't pay attention, since the color $color ",
            "wasn't a choice.\n" );
    }

    print( "\n" );

    print( "Thanks, $userName. It was most interesting to learn that your\n" );
    print( "favorite programming language is $programmingLang and that\n" );
    print( "your favorite color of M&Ms is $color.\n\n" );
    print( "Good-bye!\n\n" );