4.1. Installation
• On Microsoft Windows install ActivePerl from http://www.activestate.com/
• On UNIX/Linux you usually have it installed in /usr/bin/perl or install ActivePerl
4.2. Editors, IDEs
• Emacs http://www.gnu.org/software/emacs/
• vi, vim, gvim http://www.vim.org/
• Crimson Editor http://www.crimsoneditor.com/
• Notepad++ http://notepad-plus.sourceforge.net/
• Textpad http://www.textpad.com/
• Multi-Edit http://www.multiedit.com/
• Komodo of ActiveState http://www.activestate.com/

• Eclipse http://www.eclipse.org/
• SlickEdit http://www.slickedit.com/
4.3. Environment
On the command line one can type:
perl -e "print 42"
perl -v
perl -V 

4
Chapter 4. First steps
Example 4-1. examples/intro/hello_world.pl
#!/usr/bin/perl
use strict;
use warnings;
print "Hello world\n";
print 42, "\n";
run it by typing perl hello_world.pl
On unix you can also make it executable: chmod u+x hello_world.pl and then run like: ./hello_world.pl
A couple of notes
• Strings and numbers
• Strings must be quoted, you can use special characters such as "\n"
• The print statement (Output) - gets comma delimitered list of things
• ; after every statement
4.4. Safety net
#!/usr/bin/perl
use strict;
use warnings;
You should always use them as they are a safety net helping reduce mistakes.
It is usually very hard to add this safety net after you already have some code.
If the warnings you get don’t make sense add
use diagnostics;
line and you will get more verbose warnings.
Why are use warnings and use strict so important even in small (< 100 lines) scripts ?
• Helps avoiding trouble with recoursive functions
• Helps avoiding typos in variable names
• Disables unintentional symbolic references
• Reduces debugging time
• Enables/enforces better coding standard => cleaner code, maintainability

Chapter 4. First steps
4.5. Comments
# Comments for other developers
print 42; # the answer
4.6. Perl documentation
perldoc perl
perldoc perlsyn
perldoc perlfunc
perldoc -f print
perldoc -q sort
perldoc perlrun
perldoc strict
perldoc warnings
An index: http://www.szabgab.com/articles/perlindex.html
Web based: http://perldoc.perl.org/
4.7. POD - Plain Old Documentation
Example 4-2. examples/intro/documentation.pl
#!/usr/bin/perl
use strict;
use warnings;
print "Hello, there is no more code here\n";
=head1 Explaining how PODs work
Documentation starts any time there is a =tag
at the beginning of a line (tag can be any word)
and ends where there is a =cut at the beginning
of a line.
Around the =tags you have to add empty rows.
A =tag can be anything but there are some tags
that actually have meaning:
=head1 Main heading

Chapter 4. First steps
=head2 Subtitle
=over 4 start of indentation
=item * element
=back end of indentation
Documentation of PODs can be found in B
See a few examples:
=head1 Main heading
text after main heading
=head2 Less important title
more text
some text shown verbatim
more verbatim text typed in indented to the right
=over 4
=item *
Issue
=item *
Other issue
=back
documentation ends here
=cut
print "Just documentation\n";
perl examples/intro/documentation.pl
perldoc examples/intro/documentation.pl
4.8. Exercise: Hello world
Try your environment:

Chapter 4. First steps
• Make sure you have access to the right version of Perl (5.8.x)
• Check you can read the documentation.
• Check if you have a good editor with syntax highlighting
• Write a simple script that prints Hello world
• Add comments to your code
• Add user documentation to your code
8
Chapter 5. Scalars
A single piece of data either a number or a string is called a ’scalar’ in Perl.
5.1. Numbers - integers, real or floating-point
integer (decimal)
26
1_234_567_890
integer (hex/oct/binary)
0x1a # hex also written as hex("1a");
032 # oct also written as oct("32");
0b11010 # binary also written as oct("0b11010");
# all 3 equal to 26 decimal
real or floating-point
3.5e+3 # 3500
5.2. Scalar variables (use my)
• Scalar variables always start with a $ sign, name is alphanumeric (a-zA-Z0-9) and underscore (_)
• A scalar variable can hold either a string or a number
• Value assignment to varaible is done by the = sign
• Use the my keyword to declare variables (optional but recommended)
$this_is_a_long_scalar_variable
$ThisIsAlsoGoodButWeUseItLessInPerl
$h
$H # $h and $H are two different variables
Example 5-1. examples/scalars/scalar_variables.pl
#!/usr/bin/perl
use strict;
use warnings;
my $greeting = "Hello world\n";
my $the_answer = 42;
print $greeting;
9
Chapter 5. Scalars
print $the_answer, "\n";
A scalar can hold either string or numerical value. They can be changed any
time. If a value was not given it holds the special value ’undef’.
my $x; # the value is a special value called ’undef’
5.3. Greeting with a name, Variable interpolation
Example 5-2. examples/scalars/variable_interpolation.pl
#!/usr/bin/perl
use strict;
use warnings;
my $name = "Foo";
print "Hello ", $name, " - how are you ?\n";
print "Hello $name - how are you ?\n";
5.4. User Input
Example 5-3. examples/scalars/read_from_stdin.pl
#!/usr/bin/perl
use strict;
use warnings;
print "Enter your name, please: ";
my $name = ;
print "Hello $name, how are you ?\n";
• STDIN - Standard Input (usually it is the keyboard)
• Reading one line (till ENTER) from STDIN
$ perl examples/read_from_stdin.pl
Enter your name, please: Foo
Hello Foo
, how are you ?
There is this problem of the newline
10
Chapter 5. Scalars
5.5. chomp
Example 5-4. examples/scalars/read_from_stdin_chomp.pl
#!/usr/bin/perl
use strict;
use warnings;
print "Enter your name, please: ";
my $name = ;
chomp $name;
print "Hello $name, how are you ?\n";
chomp will remove the new line "\n" character from the end of the string if there was one.
5.6. Numerical Operators
Example 5-5. examples/scalars/numerical_operators.pl
#!/usr/bin/perl
use strict;
use warnings;
my $x = 3;
my $y = 11;
my $z = $x + $y;
print "$z\n"; # 14
$z = $x * $y;
print "$z\n"; # 33
print $y / $x, "\n"; # 3.66666666666667
$z = $y % $x; # (modulus)
print "$z\n"; # 2
$z += 14; # is the same as $z = $z + 14;
print "$z\n"; # 16
$z++; # is the same as $z = $z + 1;
$z--; # is the same as $z = $z - 1;
$z = 23 ** 2; # exponentiation
print "$z\n"; # 529
11
Chapter 5. Scalars
Example 5-6. examples/scalars/autoincrement.pl
#!/usr/bin/perl
use strict;
use warnings;
my $x = 7;
# Postfix ++ increments AFTER the OLD value was used
my $y = $x++;
print "y = $y, x = $x\n"; # y = 7, x = 8,
$x = 7;
$y = ++$x;
print "y = $y, x = $x\n"; # y = 8, x = 8
See also perldoc perlop for all the operators.
5.7. String Operators
Example 5-7. examples/scalars/string_operators.pl
#!/usr/bin/perl
use strict;
use warnings;
my $x = "Hello";
my $y = "World";
# . is the concatenation operator, ataching ons string after the other
my $z = $x . " " . $y; # the same as "$x $y"
print $z, "\n"; # Hello World
my $w = "Take " . (2 + 3); # you cannot write "Take (2 + 3)" here
print "$w\n"; # Take 5
$z .= "! "; # the same as $z = $z . "! ";
print "’$z’\n"; # ’Hello World! ’
# x is the string repetition operator
my $q = $z x 3;
print "’$q’\n"; # ’Hello World! Hello World! Hello World! ’
See also perldoc perlop for all the operators.
12
Chapter 5. Scalars
5.8. Dividing two numbers given by the user
Ask the user for two numbers and divide the first by the second number.
Example 5-8. examples/scalars/divide.pl
#!/usr/bin/perl
use strict;
use warnings;
print "First number: ";
my $x = ;
chomp $x;
print "Second number: ";
my $y = ;
chomp $y;
my $z = $x / $y;
print "The result is $z\n";
$ perl examples/divide.pl
First number: 27
Second number: 3
9
$ perl examples/divide.pl
First number: 27
Second number: 0
Illegal division by zero at examples/divide.pl line 9, line 2.
5.9. Fixing the problem: Conditional statements: if
Sometimes based on some condition a piece of code has to be executed or not.
Example 5-9. examples/scalars/if_conditional.pl
#!/usr/bin/perl
use strict;
use warnings;
print "First number: ";
my $x = ;
chomp $x;
print "Second number: ";
my $y = ;
chomp $y;
13
Chapter 5. Scalars
if ($y == 0) {
print "Cannot divide by zero\n";
} else {
my $z = $x / $y;
print "The result is $z\n";
}
5.10. Syntax of if statement
{} are always required
if (COND) {
STATEMENTs;
}
if (COND) {
STATEMENTs;
} else {
STATEMENTs;
}
if (COND_1) {
A_STATEMENTs;
} else {
if (COND_2) {
B_STATEMENTs;
} else {
if (COND_3) {
C_STATEMENTs;
} else {
D_STATEMENTs;
}
}
}
if (COND_1) {
A_STATEMENTs;
} elsif (COND_2) {
B_STATEMENTs;
} elsif (COND_3) {
C_STATEMENTs;
} else {
D_STATEMENTs;
}
14
Chapter 5. Scalars
5.11. Comparison operators
Table 5-1. Comparison operators
Numeric String (ASCII) Meaning
== eq equal
!= ne not equal
< lt less than
> gt greater than
<= le less than or equal
>= ge greater then or equal
5.12. String - Number conversion
Example 5-10. examples/scalars/string_number.pl
#!/usr/bin/perl
use strict;
use warnings;
print 3 . "", "\n";
print 3.1 . "", "\n";
print "3" + 0, "\n";
print "3.1" + 0, "\n";
print "3x" + 0, "\n"; # warning: Argument "3x" isn’t numeric in addition (+)
print "3\n" + 0, "\n";
print "3x7" + 0, "\n"; # warning: Argument "3x7" isn’t numeric in addition (+)
print "" + 0, "\n"; # warning: Argument "" isn’t numeric in addition (+)
print "z" + 0, "\n"; # warning: Argument "z" isn’t numeric in addition (+)
print "z7" + 0, "\n"; # warning: Argument "z7" isn’t numeric in addition (+)
5.13. Compare values
Example 5-11. examples/scalars/compare_values.pl
#!/usr/bin/perl
use strict;
use warnings;
my $first = ;
chomp $first;
15
Chapter 5. Scalars
my $other = ;
chomp $other;
if ($first == $other) {
print "The two numbers are the same\n";
} else {
print "The two numbers are NOT the same\n";
}
if ($first eq $other) {
print "The two strings are the same\n";
} else {
print "The two strings are NOT the same\n";
}
if ($first > $other) {
print "First is a BIGGER number\n";
} else {
print "First is a smaller number\n";
}
if ($first gt $other) {
print "First is a BIGGER string\n";
} else {
print "First is a smaller string\n";
}
5.14. Compare values - examples
Table 5-2. Compare values
Expression Value
"12.0" == 12 TRUE
"12.0" eq 12 FALSE
2 < 3 TRUE
2 lt 3 TRUE
12 > 3 TRUE
12 gt 3 FALSE !
"" == "hello" TRUE ! (Warning)
"" eq "hello" FALSE
"hello" == "world" TRUE ! (Warning)
"hello" eq "world" FALSE
When reading from STDIN you can always expect a string
16
Chapter 5. Scalars
Example 5-12. examples/scalars/is_empty_string.pl
#!/usr/bin/perl
use strict;
use warnings;
my $input = ;
chomp $input;
if ($input == "") { # wrong! use eq
# empty string
}
5.15. Boolean expressions (logical operators)
Table 5-3. Logical operators
and &&
or ||
not !
if (COND and COND) {
}
if (COND or COND) {
}
if (not COND) {
}
See also perldoc perlop for precedence and associativity tables and/or use () to define the order of
evaluation.
5.16. TRUE and FALSE
The FALSE values:
undef
""
0 0.0 00000 0e+10
"0"
Other values such as the following are TRUE
1
"00"
17
Chapter 5. Scalars
"0\n"
if ($z) {
# $z is true
}
if (defined $x) {
# $x is defined (not undef)
}
5.17. Your Salary is in Danger - Short-Circuit
If perl already knows the final value of a boolean expression after computing
only part of it, perl will NOT calculate the rest of the expression:
if ($my_money > 1_000_000 or $my_salary > 10_000) {
# I can live well
}
if ($my_money > 1_000_000 or $my_salary++ > 10_000) {
# I can live well
}
5.18. String functions
• length STRING - number of characters
• lc STRING - lower case
• uc STRING - upper case
• index STRING, SUBSTRING - the location of a substring given its content
Example 5-13. examples/scalars/string_functions.pl
#!/usr/bin/perl
use strict;
use warnings;
my $s = "The black cat jumped from the green tree";
print index $s, "ac"; # 6
print "\n";
print index $s, "e"; # 2
print "\n";
print index $s, "e", 3; # 18
18
Chapter 5. Scalars
print "\n";
print index $s, "dog"; # -1
print "\n";
print rindex $s, "e"; # 39
print "\n";
print rindex $s, "e", 38; # 38
print "\n";
print rindex $s, "e", 37; # 33
print "\n";
5.19. String functions
substr STRING, OFFSET, LENGTH - the content of a substring given its location
Example 5-14. examples/scalars/string_functions_substr.pl
#!/usr/bin/perl
use strict;
use warnings;
my $s = "The black cat climbed the green tree";
my $z;
$z = substr $s, 4, 5; # $z = black
print "$z\n";
$z = substr $s, 4, -11; # $z = black cat climbed the
print "$z\n";
$z = substr $s, 14; # $z = climbed the green tree
print "$z\n";
$z = substr $s, -4; # $z = tree
print "$z\n";
$z = substr $s, -4, 2; # $z = tr
print "$z\n";
$z = substr $s, 14, 7, "jumped from"; # $z = climbed
print "$z\n";
print "$s\n"; # $s = The black cat jumped from the green tree
5.20. Strings - Double quoted
print "normal string"; # normal string
print "two\nlines"; # two
# lines
print "another ’string’"; # another ’string’
my $name = "Foo";
19
Chapter 5. Scalars
print "Hello $name, how are you?"; # Hello Foo, how are you?
print "His "real" name is Foo"; # ERROR
print "His \"real\" name is Foo"; # His "real" name is Foo
print "His \"real\" name is \"$name\""; # His "real" name is "Foo"
print qq(His "real" name is "$name"); # His "real" name is "Foo"
print qq(His "real" name is ($name)); # His "real" name is (Foo)
print qq{His "real" name is ($name)}; # His "real" name is (Foo)
In double quoted strings you can use the following:
Backslash escapes sequences like \n \t
see in perldoc perlop
Variable interpolation
5.21. Strings - Single quoted
print ’one string’; # one string
print ’a\n’; # a\n
print ’a $name’; # a $name
print ’another "string"’; # another "string"
There are only two special characters in this kind of string the ’
and the \ at the end of the string
print ’a’b’; # ERROR - perl will see the string ’a’
# and something attached to it
print ’a\’b’; # a’b
print ’ab\’; # ERROR - perl will not see the closing ’
# as it will think it was escaped
print ’ab\\’; # ab\
print q(His "variable" name ’$name’\n); # His "variable" name is ’$name’\n
5.22. Scope of variables
Variables defined within a block {} are hiding more global
variables with the same name.
They are descrutced when leaving the block.
20
Chapter 5. Scalars
Example 5-15. examples/scalars/scope.pl
#!/usr/bin/perl
use strict;
use warnings;
my $fname = "Foo";
my $lname = "Bar";
print "$fname\n"; # Foo
print "$lname\n"; # Bar
{
my $email = ’foo@bar.com’;
print "$email\n"; # foo@bar.com
print "$fname\n"; # Foo
print "$lname\n"; # Bar
my $lname = "Moo";
print "$lname\n"; # Moo
}
# $email does not exists
print "$fname\n"; # Foo
print "$lname\n"; # Bar
5.23. Random numbers
Example 5-16. examples/scalars/random.pl
#!/usr/bin/perl
use strict;
use warnings;
my $num = rand(); # returns a random number: 0 <= NUMBER < 1
my $n = rand(100); # returns a number: 0 <= NUMBER < 100
my $i = int(3.12); # returns the whole part of the number (3 in this case)
my $number = int(rand(100)); # returns a whole number: 0 <= NUMBER < 100
5.24. Exercises: Simple Calcualtor
Write a script that will ask for a number, an operator (+,*,-,/)
and another number. Compute the result and print it out.
21
Chapter 5. Scalars
5.25. Number Guessing game
Using the rand() function the computer thinks about a number.
The user has to guess the number. After the user types in
his guess the computer tells if this was bigger or smaller than
the number it generated.
At this point there is no need to allow the user to guess several times.
5.26. Solution: Simple Calulator
Example 5-17. examples/scalars/basic_calculator.pl
#!/usr/bin/perl
use strict;
use warnings;
print "Type in 2 numbers and an operator and I’ll print the results\n\n";
print "First number: ";
my $first = ;
chomp($first);
print "Second number: ";
my $other = ;
chomp($other);
print "The operator: ";
my $oper = ;
chomp($oper);
my $result;
if ($oper eq "+") { $result = $first + $other; }
if ($oper eq "-") { $result = $first - $other; }
if ($oper eq "*") { $result = $first * $other; }
if ($oper eq "/") {
if ($other == 0) {
print "\nCannot divide by 0\n";
$result = "ERROR";
} else {
$result = $first / $other;
}
}
print "\nResult of $first $oper $other = $result\n";
# What if the given operator is not one of the 4 ?
22
Chapter 5. Scalars
5.27. Solution: Simple Calulator (using eval)
Example 5-18. examples/scalars/basic_calculator_eval.pl
#!/usr/bin/perl
use strict;
use warnings;
print "Type in 2 numbers and an operator and I’ll print the results\n\n";
print "First number: ";
my $first = ;
chomp($first);
print "Second number: ";
my $other = ;
chomp($other);
print "The operator: ";
my $oper = ;
chomp($oper);
my $result = eval "$first $oper $other";
print "\nResult of $first $oper $other = $result\n";
23
Chapter 6. Files
6.1. die, warn, exit
exit() - exits from the program
warn() - writes to STDERR
die() - writes to STDERR and exits from the program
warn "This is a warning";
This is a warning at script.pl line 132.
If no \n at the end of the string both warn and die add the
name of file and line number and possibly the chunk of the input.
6.2. Opening file for reading
While working over most of the operating systems today, no program can
access a file directly. This is in order to allow the Operaring System
to apply user rights.
Before you can read from a file you have to ask the Operating System to "open"
it for you. When opening a file you provide a variable that will become your
handle to the opened file. It is called a filehandle.
my $filename = "input.txt";
open(my $fh, "<", $filename);
close $fh;
6.3. Opening a file
my $filename = "some_filename");
open(my $fhb, "<", $filename); # read
open(my $fhc, ">", $filename); # write
open(my $fhd, ">>", $filename); # append
open(my $fhe, "+<", $filename); # read and write
6.4. Opening a file - error handling
• $! - error message from the Operating system
24
Chapter 6. Files
Example 6-1. examples/files/open_with_if.pl
#!/usr/bin/perl
use strict;
use warnings;
my $filename = "input.txt";
if (open my $in, "<", $filename) {
# do your thing here
# no need to explicitly close the file
} else {
warn "Could not open file ’$filename’. $!";
}
# here the $in filehandle is not accessible anymore
A more Perlish way to open a file and exit with error message if you could not open the file:
Example 6-2. examples/files/open_with_die.pl
#!/usr/bin/perl
use strict;
use warnings;
my $filename = "input.txt";
open(my $fh, "<", $filename) or die "Could not open file ’$filename’. $!";
# do your thing here
close $fh;
6.5. Opening a missing file
Example 6-3. examples/files/open_missing_file.pl
#!/usr/bin/perl
use strict;
use warnings;
if (open my $fh, ’<’, "nosuch") {
# should do here something
} else {
warn $!;
}
The error message we get:
No such file or directory at examples/files/open_missing_file.pl line 7.
25
Chapter 6. Files
6.6. Read one line from a file
Example 6-4. examples/files/read_line.pl
#!/usr/bin/perl
use strict;
use warnings;
# Reading a line from a file (or rather from a filehandle)
my $filename = "input.txt";
if (open my $data, "<", $filename) {
my $line = <$data>;
print $line;
} else {
warn "Could not open file ’$filename’: $!";
}
6.7. Process an entire file line by line (while, cat)
• while - executes as long as there is something in $line, as long as there are lines in the file
• Loop over file (name hardcoded) and print every line (UNIX cat)
Example 6-5. examples/files/cat.pl
#!/usr/bin/perl
use strict;
use warnings;
my $filename = "input.txt";
open(my $fh, "<", $filename) or die "Could not open ’$filename’\n";
while (my $line = <$fh>) {
print $line;
}
Instead of printing the line you could do anything with it.
6.8. Write to a file
Example 6-6. examples/files/write_file.pl
#!/usr/bin/perl
use strict;
use warnings;
my $filename = "report.txt";
26
Chapter 6. Files
open my $fh, ’>’, $filename or die "Could not open file ’$filename’ $!";
print $fh "Report by: Foo Bar\n";
print $fh "-" x 20;
print $fh "\n";
6.9. Sum of numbers in a file
Example 6-7. examples/files/count_sum_write.pl
#!/usr/bin/perl
use strict;
use warnings;
# given a file with a number on each row, print the sum of the numbers
my $sum = 0;
my $filename = "numbers.txt";
open(my $fh, "<", $filename) or die "Could not open ’$filename’\n";
while (my $line = <$fh>) {
$sum += $line;
}
print "The total value is $sum\n";
6.10. Analyze the Apache log file
Example 6-8. examples/files/apache_access.log
127.0.0.1 - - [10/Apr/2007:10:39:11 +0300] "GET / HTTP/1.1" 500 606 "-" "Mozilla/5.0 (X11; U; 127.0.0.1 - - [10/Apr/2007:10:39:11 +0300] "GET /favicon.ico HTTP/1.1" 200 766 "-" "Mozilla/139.12.0.2 - - [10/Apr/2007:10:40:54 +0300] "GET / HTTP/1.1" 500 612 "-" "Mozilla/5.0 (X11; 139.12.0.2 - - [10/Apr/2007:10:40:54 +0300] "GET /favicon.ico HTTP/1.1" 200 766 "-" "Mozilla/127.0.0.1 - - [10/Apr/2007:10:53:10 +0300] "GET / HTTP/1.1" 500 612 "-" "Mozilla/5.0 (X11; U; 127.0.0.1 - - [10/Apr/2007:10:54:08 +0300] "GET / HTTP/1.0" 200 3700 "-" "Mozilla/5.0 (X11; 127.0.0.1 - - [10/Apr/2007:10:54:08 +0300] "GET /style.css HTTP/1.1" 200 614 "http://pti.local/" 127.0.0.1 - - [10/Apr/2007:10:54:08 +0300] "GET /img/pti-round.jpg HTTP/1.1" 200 17524 "http://127.0.0.1 - - [10/Apr/2007:10:54:21 +0300] "GET /unix_sysadmin.html HTTP/1.1" 200 3880 "http://217.0.22.3 - - [10/Apr/2007:10:54:51 +0300] "GET / HTTP/1.1" 200 34 "-" "Mozilla/5.0 (X11; U; 217.0.22.3 - - [10/Apr/2007:10:54:51 +0300] "GET /favicon.ico HTTP/1.1" 200 11514 "-" "Mozilla/217.0.22.3 - - [10/Apr/2007:10:54:53 +0300] "GET /cgi/pti.pl HTTP/1.1" 500 617 "http://contact.127.0.0.1 - - [10/Apr/2007:10:54:08 +0300] "GET / HTTP/0.9" 200 3700 "-" "Mozilla/5.0 (X11; 217.0.22.3 - - [10/Apr/2007:10:58:27 +0300] "GET / HTTP/1.1" 200 3700 "-" "Mozilla/5.0 (X11; 217.0.22.3 - - [10/Apr/2007:10:58:34 +0300] "GET /unix_sysadmin.html HTTP/1.1" 200 3880 "http://217.0.22.3 - - [10/Apr/2007:10:58:45 +0300] "GET /talks/Fundamentals/read-excel-file.html HTTP/ 27
Chapter 6. Files
Example 6-9. examples/files/apache_log_hosts.pl
#!/usr/bin/perl
use strict;
use warnings;
my $file = "examples/files/apache_access.log";
open my $fh, ’<’, $file or die "Could not open ’$file’: $!";
my $good;
my $bad;
while (my $line = <$fh>) {
chomp $line;
my $length = index ($line, " ");
my $ip = substr($line, 0, $length);
if ($ip eq "127.0.0.1") {
$good++;
} else {
$bad++;
}
}
print "$good $bad\n";
6.11. Open files in the old way
In old version of perl (before 5.6) we could not use scalar variabsles as file
handles so we used uppercase letters such as XYZ or INPUT, QQRQ or FILEHANDLE.
Also the function had only 2 parameters.
Example 6-10. examples/files/open_file_old.pl
#!/usr/bin/perl
use strict;
use warnings;
my $filename = "data.txt";
open(FH, $filename);
my $line = ;
close FH;
open(FH, ">$filename");
print FH "data";
close FH;
Security problems.
28
Chapter 6. Files
Being global, difficult to pass as parameter to functions.
6.12. Exercise: Add more statistics
Take the script from the previous example (count_sum_write.pl)
and in addition to the sum of the numbers print also
minimum
maximum
average
median and standard deviation are probably too difficult for now.
6.13. Exercise: Write report to file
Take the exercise creating statistics of the numbers.txt file and
write the results to the numbers.out file.
minimum: -17
maximum: 98
total: 126
count: 6
average: 21
You might need to look up the documentation of the printf
in order to have align the columns.
6.14. Exercise: Analyze Apache - number of successful
hits
In the Apache log file after the "GET something HTTP/1.1" part there is the
result code of the requests. 200 is OK the rest might be some failure.
Please create a report showing how many of the hits were successful (200)
and how many were something else.
Could you put all the lines in either of the categories?
29
Chapter 6. Files
6.15. Solution: Add more statistics
Example 6-11. examples/files/statistics.pl
#!/usr/bin/perl
use strict;
use warnings;
my $total = 0;
my $count = 0;
my $min;
my $max;
my $filename = "numbers.txt";
open(my $fh, "<", $filename) or die "Could not open ’$filename’\n";
while (my $line = <$fh>) {
chomp $line;
$total += $line;
if (not $count) {
$min = $line;
$max = $line;
}
$count++;
if ($line < $min) {
$min = $line;
}
if ($line > $max) {
$max = $line;
}
}
if (not defined $min) {
print "No values were given\n";
} else {
print "Min: $min Max: $max Total: $total count: $count Average: ",
$total / $count, "\n";
}
6.16. Solution: Analyze Apache - number of successful
hits
Example 6-12. examples/files/apache_log_result_code.pl
#!/usr/bin/perl
use strict;
use warnings;
30
Chapter 6. Files
my $file = "examples/files/apache_access.log";
open my $fh, ’<’, $file or die "Could not open ’$file’: $!";
my $good = 0;
my $bad = 0;
my $ugly = 0;
while (my $line = <$fh>) {
chomp $line;
my $request = q( HTTP/1.1" );
my $start_request = index ($line, $request);
my $result;
if ($start_request >= 0) {
my $end_request = index($line, " ", $start_request + length($request));
$result = substr($line, $start_request + length($request), $end_request-$start_request #print "$start_request, $end_request ’$result’\n";
} else {
my $request = q( HTTP/1.0" );
my $start_request = index ($line, $request);
if ($start_request >= 0) {
my $end_request = index($line, " ", $start_request + length($request));
$result = substr($line, $start_request + length($request), $end_request-$start_request #print "$start_request, $end_request ’$result’\n";
} else {
#print "ERROR: Unrecognized Line: $line\n";
}
}
if (defined $result) {
if ($result eq "200") {
$good++;
} else {
$bad++;
}
} else {
$ugly++;
}
}
print "Good: $good\n";
print "Bad: $bad\n";
print "Ugly: $ugly\n";
# Disclaimer: this is not an optimal solution.
# We will see a much better one after learning functions, regular expressions
31
Chapter 6. Files
6.17. Solution: Write report to file
Example 6-13. examples/files/write_report_to_file.pl
#!/usr/bin/perl
use strict;
use warnings;
my $total = 0;
my $count = 0;
my $min;
my $max;
my $filename = "examples/files/numbers.txt";
open(my $fh, "<", $filename) or die "Could not open ’$filename’\n";
while (my $line = <$fh>) {
chomp $line;
$total += $line;
if (not $count) {
$min = $line;
$max = $line;
}
$count++;
if ($line < $min) {
$min = $line;
}
if ($line > $max) {
$max = $line;
}
}
open my $out, ’>’, ’numbers.out’;
if (not defined $min) {
print $out "No values were given\n";
} else {
printf($out "Minimum: %5s\n", $min);
printf($out "Maximum: %5s\n", $max);
printf($out "Total: %5s\n", $total);
printf($out "Count: %5s\n", $count);
printf($out "Average: %5s\n", $total / $count);
}
32
Chapter 7. Lists and Arrays
7.1. List Literals, list ranges
Things in () separated by commas are called a list of things.
A list is an ordered set of scalar values.
Examples of lists:
(1, 5.2, "apple") # 3 values
(1,2,3,4,5,6,7,8,9,10) # nice but we are too lazy, so we write this:
(1..10) # same as (1,2,3,4,5,6,7,8,9,10)
(’a’..’z’) # all the lowercase letters
("apple", "banana", "peach", "blueberry") # is the same as
qw(apple banana peach blueberry) # quote word
($x, $y, $z) # We can also use scalar variables as elements of a list
7.2. List Assignment
my ($x, $y, $z);
($x, $y, $z) = (2, 3, 7); # nearly the same as $x=2; $y=3; $z=7;
($x, $y) = (8, 1, 5); # ignore 5
($x, $y, $z) = (3, 4); # $z will be undef
A regular question on job interviews:
How can we swap the values of 2 variables, let say $x and $y?
7.3. loop over elements of list with foreach
• list
• foreach ITEM (LIST) {BLOCK}
• my - in the foreach loop
Example 7-1. examples/arrays/list_colors.pl
#!/usr/bin/perl
use strict;
use warnings;
33
Chapter 7. Lists and Arrays
foreach my $color ("Blue", "Yellow", "Brown", "White") {
print "$color\n";
}
Blue
Yellow
Brown
White
7.4. Create an Array, loop over with foreach
Example 7-2. examples/arrays/list_colors_array.pl
#!/usr/bin/perl
use strict;
use warnings;
my @colors = ("Blue", "Yellow", "Brown", "White");
print "@colors\n";
foreach my $color (@colors) {
print "$color\n";
}
Blue Yellow Brown White
Blue
Yellow
Brown
White
7.5. Array Assignment
You can also mix the variables on the right side and if there are arrays on the right side the whole thing
becomes one flat array !
my $owner = "Moose";
my @tenants = qw(Foo Bar);
my @people = ($owner, ’Baz’, @tenants); # Moose Baz Foo Bar
my ($x, @y, @z);
($x, @y) = (1, 2, 3, 4); # $x is 1; @y is (2, 3, 4)
($x, @y, @z) = (1, 2, 3, 4); # $x is 1; @y is (2, 3, 4) @z is empty: ()
@y = (); # Emptying an array
34
Chapter 7. Lists and Arrays
7.6. foreach loop on numbers
foreach my $i (1..10) {
print "$i\n";
}
1
2
3
4
5
6
7
8
9
10
7.7. Array index (menu)
• $#array - the largest index
• $array[1] - array elements are scalar
Example 7-3. examples/arrays/color_menu.pl
#!/usr/bin/perl
use strict;
use warnings;
my $color;
my @colors = ("Blue", "Yellow", "Brown", "White");
print "Please select a number:\n";
foreach my $i (0..$#colors) {
print "$i) $colors[$i]\n";
}
my $num = ;
chomp($num);
if (defined $colors[$num]) {
$color = $colors[$num];
} else {
print "Bad selection\n";
exit;
}
print "The selected color is $color\n";
35
Chapter 7. Lists and Arrays
7.8. Command line parameters
• @ARGV - all the arguments on the command line
• $ARGV[0] - the first argument
• $0 - name of the program
• perl read_argv.pl blue
Example 7-4. examples/arrays/read_argv.pl
#!/usr/bin/perl
use strict;
use warnings;
my $color;
if (defined $ARGV[0]) {
$color = $ARGV[0];
}
my @colors = ("Blue", "Yellow", "Brown", "White");
if (not defined $color) {
print "Please select a number:\n";
foreach my $i (0..$#colors) {
print "$i) $colors[$i]\n";
}
my $num = ;
chomp($num);
if (defined $colors[$num]) {
$color = $colors[$num];
} else {
print "Bad selection\n";
exit;
}
}
print "The selected color is $color\n";
7.9. Process command line parameters, use modules
• use Module;
• scalar reference
Example 7-5. examples/arrays/process_command_line.pl
#!/usr/bin/perl
use strict;
use warnings;
36
Chapter 7. Lists and Arrays
use Getopt::Long qw(GetOptions);
my $color;
GetOptions("color=s" => \$color) or die "Usage: $0 [--color COLOR]\n";
my @colors = ("Blue", "Yellow", "Brown", "White");
if (not defined $color) {
print "Please select a number:\n";
foreach my $i (0..$#colors) {
print "$i) $colors[$i]\n";
}
my $num = ;
chomp($num);
if (defined $colors[$num]) {
$color = $colors[$num];
} else {
print "Bad selection\n";
exit;
}
}
print "The selected color is $color\n";
7.10. Module documentation
perldoc Getopt::Long
http://perldoc.perl.org/Getopt/Long.html
perldoc Cwd
http://perldoc.perl.org/Cwd.html
7.11. process csv file
• split
Example 7-6. examples/arrays/process_csv_file.csv
Foo,Bar,10,home
Orgo,Morgo,7,away
Big,Shrek,100,US
Small,Fiona,9,tower
37
Chapter 7. Lists and Arrays
Example 7-7. examples/arrays/process_csv_file.pl
#!/usr/bin/perl
use strict;
use warnings;
my $file = ’process_csv_file.csv’;
if (defined $ARGV[0]) {
$file = $ARGV[0];
}
my $sum = 0;
open(my $data, ’<’, $file) or die "Could not open ’$file’\n";
while (my $line = <$data>) {
chomp $line;
my @columns = split ",", $line;
$sum += $columns[2];
}
print "$sum\n";
7.12. process csv file (short version)
Example 7-8. examples/arrays/process_csv_file_short.pl
while (<>) {
$sum += (split ",")[2];
}
print "$sum\n";
Use the following command to run the script:
perl examples/arrays/process_csv_file_short.pl examples/arrays/process_csv_file.csv
See also the oneliners
7.13. process csv file using Text::CSV_XS
What if there is a field called: "Foo, Bar" ?
Example 7-9. examples/arrays/process_csv_file_module.csv
Foo,Bar ,10,home
Orgo,"Morgo, Hapci",7,away
Big,Shrek,100,US
Small,Fiona,9,tower
38
Chapter 7. Lists and Arrays
Example 7-10. examples/arrays/process_csv_file_module.pl
#!/usr/bin/perl
use strict;
use warnings;
use Text::CSV_XS;
my $csv = Text::CSV_XS->new();
my $file = ’process_csv_file_module.csv’;
if (defined $ARGV[0]) {
$file = $ARGV[0];
}
my $sum = 0;
open(my $data, ’<’, $file) or die "Could not open ’$file’\n";
while (my $line = <$data>) {
chomp $line;
if ($csv->parse($line)) {
my @columns = $csv->fields();
$sum += $columns[2];
} else {
warn "Line could not be parsed: $line\n";
}
}
print "$sum\n";
7.14. Join
my @fields = qw(Foo Bar foo@bar.com);
my $line = join ";", @fields;
print "$line\n"; # Foo;Bar;foo@bar.com
7.15. Exercise: improve the color selector
Take the process_command_line.pl script improve in several ways:
- Check if the value given on the command line is indeed one
of the possible values and don’t let other colors pass.
- Allow a --force flag that will disregard the previously implemented restriction.
- Read the names of the colors from a file called colors.txt
- Let the user pass the name of the color file using the --filename FILENAME option.
39
Chapter 7. Lists and Arrays
7.16. Improve the Number Guessing game from the
earlier chapter
Let the user guess several times (with responses each time) till he finds
the hidden number.
Allow the user to type
n - skip this game and start a new one
s - show the hidden value
x - exit
Now I can tell you that what you have is actually a 1 dimensional space fight
and you are trying to guess the distance of the enemy space ship.
As it is not a sitting duck, after every shot the spaceship can randomly move +2-2.
For trainng purposes you might want to limit the outer spaces to 0-100.
Make sure the enemy does not wander off the training field.
Give warning if the user shoots out of space.
Keep track of the minimum and maximum number of hits (in a file).
7.17. Solution: improved color selector
Example 7-11. examples/arrays/color_selector.pl
#!/usr/bin/perl
use strict;
use warnings;
use Getopt::Long qw(GetOptions);
my $color;
my $filename = "examples/colors.txt";
my $force;
GetOptions(
"color=s" => \$color,
"filename=s" => \$filename,
"force" => \$force,
) or exit;
open(my $fh, "<", $filename)
or die "Could not open ’$filename’ for reading: $!";
my @colors;
while (my $color = <$fh>) {
chomp $color;
40
Chapter 7. Lists and Arrays
@colors = (@colors, $color);
}
# we will have a much better solution than the above 5 lines
# but we have not learned it yet
if ($color and not $force) {
my $valid_color;
foreach my $c (@colors) {
if ($c eq $color) {
$valid_color = 1;
next;
}
}
if (not $valid_color) {
print "The color ’$color’ is not valid.\n";
$color = ”;
}
}
if (not $color) {
print "Please select a number:\n";
foreach my $i (0..$#colors) {
print "$i) $colors[$i]\n";
}
my $num = ;
chomp($num);
if (defined $colors[$num]) {
$color = $colors[$num];
} else {
print "Bad selection\n";
exit;
}
}
print "The selected color is $color\n";
41
Chapter 8. Advanced Arrays
8.1. The year 19100
First, let’s talk about time.
$t = time(); # 1021924103
# returns a 10 digit long number,
# the number of seconds since 00:00:00 UTC, January 1, 1970
$x = localtime($t); # returns a string like Thu Feb 30 14:15:53 2002
$z = localtime(); # returns the string for the current time
$z = localtime(time - 60*60*24*365);
# returns the string for a year ago, same time, well almost
@y = localtime($t); # an array of time values:
# 53 15 14 30 1 102 4 61 0
# the 9 values are the following:
# 0 1 2 3 4 5 6 7 8 (the index)
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
# The localtime function is aware of what is on the left side of the = sign !!!!
# OK but where does that 19100 come from ?
$mon 0..11
$min 0..59
$sec 0..60
$year YEAR-1900 # for example 2000-1900 = 100
# but people used "19$year" instead of 1900 + $year
# which is 19100 instead of 2000
gmtime is the same just gives the time as it is in Greenwich.
8.2. SCALAR and LIST Context
my @a = ("zero", "one", "two", "three");
my @b = @a; # LIST context
my $c = @a; # SCALAR context
if (@a) {
}
while (@a) {
42
Chapter 8. Advanced Arrays
}
8.3. Context Sensitivity
Every operator creates a ’context’ let’s see a few examples
Assignment to a scalar variable creates SCALAR context:
$x = localtime();
$x = @z;
$x = SCALAR
Assignment to an array creates LIST contex:
@y = localtime();
@y = @z;
@y = LIST
# Expressions providing SCALAR context
$x = SCALAR;
$y[3] = SCALAR;
8 + SCALAR
"Foo: " . SCALAR
if (SCALAR) { ... }
while (SCALAR) { ... }
scalar(SCALAR)
# Expressions providing LIST context:
@a = LIST;
($x, $y) = LIST;
($x) = LIST;
foreach $x (LIST) {...}
join ";", LIST
print LIST
# example
@a = qw(One Two Three);
print @a; # OneTwoThree" print LIST
print 0+@a; # 3 SCALAR + SCALAR
print scalar(@a); # 3 scalar(SCALAR)
see also perldoc -f function-name
8.4. Filehandle in scalar and list context
Example 8-1. examples/arrays/filehandle_in_context.pl
#!/usr/bin/perl
43
Chapter 8. Advanced Arrays
use strict;
use warnings;
my $file = "numbers.txt";
open(my $fh, ’<’, $file) or die "Could not open ’$file’";
# reading in SCALAR context (line by line) and processing each line
while (my $row = <$fh>) {
chomp $row;
print "READ: $row\n";
}
open (my $other_fh, ’<’, $file) or die "Could not open ’$file’";
# reading in LIST context all the lines at once
my @rows = <$other_fh>;
chomp @rows;
print "READ " . @rows . " lines\n";
8.5. slurp mode
Example 8-2. examples/arrays/slurp.pl
#!/usr/bin/perl
use strict;
use warnings;
my $file = "numbers.txt";
# slurp mode
my $all;
{
open(my $fh, ’<’, $file) or die "Could not open ’$file’\n";
local $/ = undef;
$all = <$fh>;
}
8.6. File::Slurp
Example 8-3. examples/arrays/file_slurp.pl
#!/usr/bin/perl
use strict;
use warnings;
use File::Slurp qw(slurp);
44
Chapter 8. Advanced Arrays
my $filename = shift or die "Usage: $0 FILENAME\n";
my $text = slurp($filename);
8.7. pop, push
There are several functions working on arrays:
pop and push implement a LIFO stack.
pop fetches the last element of the array
returns that value and the array becomes one shorter
if the array was empty pop returns undef
LAST = pop ARRAY;
push is the opposite of pop it adds element(s) to the end of the array
It returns number of elements after the push.
PUSH ARRAY, SCALAR, ... (more SCALARs);
Example:
Example 8-4. examples/arrays/pop_push.pl
#!/usr/bin/perl
use strict;
use warnings;
my @names = ("Foo", "Bar", "Baz");
my $last_name = pop @names;
print "$last_name\n"; # Baz
print "@names\n"; # Foo Bar
push @names, "Moo";
print "@names\n"; # Foo Bar Moo
8.8. stack (pop, push)
Example 8-5. examples/arrays/reverse_polish_calculator.pl
#!/usr/bin/perl
use strict;
45
Chapter 8. Advanced Arrays
use warnings;
my @stack;
while (1) {
print ’$ ’;
my $in = ;
chomp $in;
if ($in eq "x") { last; }
if ($in eq "q") { last; }
if ($in eq "c") {
pop @stack;
next;
} # fetch the last value
if ($in eq "*") {
my $x = pop(@stack);
my $y = pop(@stack);
push(@stack, $x*$y);
next;
}
if ($in eq "+") {
my $x = pop(@stack);
my $y = pop(@stack);
push(@stack, $x + $y);
next;
}
if ($in eq "/") {
my $x = pop(@stack);
my $y = pop(@stack);
push(@stack, $y / $x);
next;
}
if ($in eq "-") {
my $x = pop(@stack);
my $y = pop(@stack);
push(@stack, $y - $x);
next;
}
if ($in eq "=") {
print pop(@stack), "\n";
next;
}
push @stack, $in;
}
46
Chapter 8. Advanced Arrays
8.9. shift, unshift
shift and unshift are working on the beginning (left side) of the array.
shift fetches the first element of an array.
It returns the fetched element and the whole array becomes one shorter and moved
to the left. Returns undef if the array was empty.
unshift adds element(s) to the beginning of an array
returns number of elements in the array after the addition
Example:
Example 8-6. examples/arrays/shift_unshift.pl
#!/usr/bin/perl
use strict;
use warnings;
my @names = ("Foo", "Bar", "Baz");
my $first = shift @names;
print "$first\n"; # Foo
print "@names\n"; # Bar Baz
unshift @names, "Moo";
print "@names\n"; # Moo Bar Baz
FIRST = shift ARRAY;
unshift ARRAY, VALUEs;
8.10. queue (shift, push)
Example 8-7. examples/arrays/queue.pl
#!/usr/bin/perl
use strict;
use warnings;
my @people = ("Foo", "Bar");
while (@people) {
my $next_person = shift @people;
print "$next_person\n"; # do something with this person
print "Type in more people:";
while (my $new = ) {
47
Chapter 8. Advanced Arrays
chomp $new;
push @people, $new;
}
print "\n";
}
8.11. shift
Example 8-8. examples/arrays/shift_argv.pl
#!/usr/bin/perl
use strict;
use warnings;
my $filename = shift or die "Usage: $0 FILENAME\n";
shift defaults to shift @ARGV
Another usage of the short circuit
Slight bug (what of the first argument is 0 or the empty string ?
Does it matter?
8.12. sort, reverse
my @reverses_names = reverse @names;
my @sorted_names = sort @names;
8.13. Advanced sort
Example 8-9. examples/arrays/sort.pl
#!/usr/bin/perl
use strict;
use warnings;
my @data = (11, 23, 12);
my @sorted = sort @data;
my @sorted_ascii = sort {$a cmp $b} @data;
my @sorted_numeric = sort {$a <=> $b} @data;
48
Chapter 8. Advanced Arrays
my @sorted_by_length
= sort {length($a) <=> length($b)} @data;
my @sorted_by_length_and_ascii
= sort {
length($a) <=> length($b)
or
$a cmp $b
} @data;
my @sorted_by_abc = sort {lc($a) cmp lc($b)} @data;
my @sorted_abc_ascii
= sort {
lc($a) cmp lc($b)
or
$a cmp $b
} @data;
8.14. Ternary operator
my $var;
if (T) {
$var = A;
} else {
$var = B;
}
my $var = T ? A : B;
r