You are on page 1of 45

Perl

File I/O and Arrays


File I/O
Perl allows to open a file to read, write, or
append
As well as pipe input or output to another
program.
We get to this piping later on
Command
open (FILEHANDLE, "filename"); #read a file
open (FILEHANDLE, "<filename");# same
open (FILEHANDLE, ">filename");# write to file
open (FILEHANDLE, ">>filename"); #append
Filehandles
<STDIN>, <STDOUT>, and <STDERR> are
filehandles that are built into perl.
The style is to write a filehandle as all caps.
Example:
open (FP, "filename");
#open filename for reading, referenced by FP
open returns a true/false value
false if it failed to open the file.
What to do if the file fails to open
Since open returns a value, we can write
statements like this
open FP, $file or die "Can 't open: $file $! \n";
open FP, $file or warn "Can't open: $file $! \n";
$! is the error message.
warn prints the string as a warning message.
die exits the program and prints a string.
A more readable version
unless (open(FP, $file) ) {
die "Can't open $file: $! \n";
}
If you have multiple files to process in sequence
FILE: foreach $file (@arrayoffilesnames) {
unless (open FP, $file) {
warn "Can't open $file: $! \n";
next FILE;
}
# statements;

}
Reading from an open file
Once the file is open, the Filehandle uses the same
syntax as <STDIN>
open FP, "file";
$line = <FP>;
When accessing a file you need <> around the
filehandle
End of File marker
Perl makes it very easy to read until the EOF
while( $line = <FP>) {
chomp($line); # remove the EOL marker.
#process input
}
It exits the loop on the end of file.
Actually the file handle returns undef, which is a false value.
closing the file
use the close command
close (filehandle);
() are optional in both close and open statements.
complete example of reading a file

unless (open FP, $file) { die "Can't open $file: $! \n";}


while ($line = <FP>) {
chomp($line);
#process file
}
close FP;
File I/O Example
Moving the chomp function

unless (open FP, $file) { die "Can't open $file: $! \n";}


while (chomp($line = <FP>)) {
Note the chomp in the read
Also works for <STDIN>
#process file
}
close FP;
Exercise 3
Using the grading script from last time
Change it to read from a file and print the grades to
the screen.

You will need to create a file and don't need a


sentinel value.
Output to a file
Using either write or append.
unless (open FO, ">file") {die "can't open file $!\n";}
You need to add the file handle to output
statements
Example
print FO "Hello world!\n";
Note: No comma after the file handle for the print
statement.
printf(FO, "Hello world!\n");
printf follows standard c format for the file handle
Open Statement and Pipes
You can "open" and executable program and
pipe the output into the perl script for
processing

open FP, "executable program |";


Everything functions just as if you opened a file
to read.
open statement and pipes (2)
Example
open FP, "ls -la |";
while (chomp($line = <FP>)) {
# process a directory list
}
close FP;
open statement and pipes (3)
Also use it to direct input to another file
open FP, "| someprogram";
print FP, "input to file";

open FP, "| someprogram|";


Not legal, an error will be generated.
In the networking lecture, we'll look at two way
pipes.
Arrays
Perl has arrays and hashing (called associative
arrays) built in.
The rest of this lecture will focus on arrays

To "declare" an array
my @arr;
Array syntax
Like c/c++ syntax
$arr[0] = 1;
But you can't use $arr++;
without the [], perl assumes it is a scalar variable.
The @ vs the $.
In most cases the $ is used when accessing
arrays, so
$arr[0] = 12;
A general rule of thumb, when accessing a slice of an
array, use $
when referring to the entire array, use @
Arrays
like all perl variables, arrays are type less
$arr[0] = 1; $arr[1] = "Jim";
And they can be as many dimensions as needed.
$arr[0][0] =1; $arr[0][1] = "Jim";

Since you can't declare how big an array is, perl allows
you to uses as many slices as needed.
The cell is only allocated in memory when you use it
So $arr[0] =1; $arr[1000] =2;
Uses only two spots in memory, instead of 1000
The indices cannot be negative on assignments.
$arr[-20] = 3; # maybe syntax error. * See slide on indices
Unused spots, return "" as a result, so
print $arr[50]; #prints nothing.
the Whole array
Initializing an array
@stuff = ("one", "two", "three");

Like, c, the first element is the 0 index


print "$stuff[0]"; # prints one
Copying one array to another
@x = @stuff;
Creating arrays from other arrays and scalar
data
@x = (@stuff, @x, "hi",1,$z); #note the ( )
First index of the array is 0
multidimensional arrays
two-dim arrays initializing
@2D = ( [1,2,3], [4,5,6], [7,8,9]);
$2d[1][1] contains 5
@x = ([@stuff], [@x], ["Hi"], [$z]);
$x[2][0] contains "hi"
Length of an array
Two methods
Uses $#arrayname
$x = $#stuff; #$x contains 2,
There are 3 items, but index of the third item is 2
OR
$x = @stuff;
May think this would give you the top element (as in stacks, we'll
get arrays as stacks later)
$x contains 3, ie there are three items in the array.
Note the $# vs the @
Also
$s[0] =1; $s[1]; $s[40];
$x = @stuff; #$x contains 41! it's for consistency
$x = $#stuff; #$x contains 40;
Length of an array (2)
2D (or more) array lengths
@arr = ([1,2],[1,2,3],[1,2,3,4]); #2D array
print $#arr; output: 2 works only the first Dim

We use indirection (pointers) to find the length


for the 2nd Dimension.
print $#{$arr[0]}; #output 1
print $#{$arr[2]}; #output 3
But
print @arr[0]; output: ARRAY(0x8281023)
Which is the pointer to the array.
Does the value exists?
$s[0] =1; $s[1]; $s[40];
There is no value for $s[2 .. 39]
You may want to check and see if a value exists
use exists operator. Returns true if the value
exists, otherwise false.
exists doesn't care if the value is true or false, only
that there is a value.
defined operator works the same.
if (exists $s[1] ) { print $s[1]; }
if ($s[1]) { print $s[1]; }
This prints only when the value of $s[1] is true. But
slice may exist, but have false value
array indices
Negative indices (bad idea, you shouldn't use them)
@arr = (1,2,3);
print $arr[-1]; # prints 3
A negative index, start from the end of the
array, but be careful, you will produce an error,
if you try and access a slice below Zero.
The indices cannot be negative on assignments
Not completely true.
So $x[-1] = 1; #syntax error, if the memory has
not be allocated or index is below zero.
But $arr[-1] = 4; #changes $arr[2] to 4
using arrays as stacks and queues
push array, LIST
push LIST onto the end of the array
push @arr, 1;
push @arr, (1, 2, 3);
same as @arr = (@arr, (1,2,3));
pop array
removes the last element of the array
$v = pop @arr;
shift array
shifts of the first value of the array.
$v = shift @arr;
unshift array, LIST
shifts LIST onto the front of the array
unshift @arr, 0;
using arrays as stacks and queues (2)
as a stack
push items on the array, the pop them back off
example:
push @a, 1; push @a, 2; push @a, 3;
$v = pop @a; # $v contains 3
$v = pop @a; # $v contains 2
$v = pop @a; # $v contains 1
$v = pop @a; # $v contains ""
as a queue
push items on, then shift them off
push @a, (1,2,3);
$v = shift @a; #$v contains 1
$v = shift @a; #$v contains 2
$v = shift @a; #$v contains 3
$v = shift @a; #v contains ""
Exercise 4
Again, use the grading program from exercise 3.
This time also put each grade value into an array
After you have finished reading the file
go through the array, find the min, max, and the average
grade.
print out this information.

Think about which control structure allows you go


process the array and how to get each value into the
array.
More on creating lists
Comma's are optional in some conditions
@releases = qw( alpha beta gamma);
qw commands Quotes the Words
Also the () don't have to parentheses. You can use
[], <>, //, {}, etc.
Some people prefer to use [], instead ().
@a = qw(a b c d);
$a[0] = "a"; $a[1] = "b"; $a[2] = "c"; $a[3] = "d";
lists in general
Like lisp, ( ) denotes a list.
And can include variables:
($a, $b, $c, $d) = ("Jim", "Sam", "Greg", $f);
$a contains "Jim", $b contains "Sam", etc.
This is important for later use.

() is a null list. ((),(),()) is the same as ()


perl treats lists as arrays.
$a = (1,2,3)[1]; # $a = 2
again useful later, when functions return arrays, but
we only want a slice of it.
lists in general (2)
$x = ( ($a, $b, $c) = ( 1,2,3));
$x contains 3, $a has 1, $b has 2, etc.
$x = ( ($a, $b) = ( 1,2,3));
$x contains 3, not 2, $a has 1, $b has 2, the 3 is lost.
$x = ( () = ( 1,2,3));
$x still contains 3, and the values are lost.

Remember ( ) is treated as an array, so $x will


have the array (list) length.
More on arrays
Clearing arrays
Either
@stuff = ();
set it equal to the empty list
OR
$#stuff = -1;
Change the array length to empty.
But does not clear the memory allocated to the
array.
use this command
undef(@stuff);
deallocates memory and clears the array
more on arrays (2)
ranges in array, same as in loops
@a = $stuff[2 .. 4];
copy only slice 2, 3, and 4 into @a
@a = $stuff[2,4,6];
copy only slice 2, 4, and 6 into @a

@a = $stuff[0, 2 .. 4];
copy only slice 0, 2,3,4 into @a
($v1,$v2,$v3) = $stuff[0,2,3];
copy slice 0 into $v1, slice 2 into $v2, etc.
functions for arrays (lists)
sort
defaults to sort based on string value ascending
array = sort array
@x = sort @y
reverse
returns a list of elements in the opposite order
@x = reverse @y;

sorting in descending order


@x = reverse sort @y;
More on sort
User defined sorting with sort
create a subroutine for sorting
We'll look at subroutines later
the sort subroutines are a special case.

Sort numerically, instead of by string value


sub numerically { $a <=> $b }
@x = sort numerically @y;

sort case insensitively


sub strcaseinsensitive { lc($a) cmp lc($b) }
@x = sort strcaseinsensitive @y;
lc function returns a lower case value
More on sort (2)
The subroutine can be written inline as well
@x = sort {$b <=> $a} @y
cmp (string compare) and <=> (numerical
compare) return -1, 0, or 1 if the left side is
greater, they are the same, or the right side is
greater, respectively.
NOTE: $a and $b are part of the sort package and
do not effect your variables.
You can also define sort routines to sort
hashed and complex variables. As well as very
complex sorting.
See the perldoc for more examples.
foreach and arrays
Since an array is just a list, we can use the
foreach statement.
@stuff = ("one", "two", "three");
foreach $val (@stuff) {
print $val, "\n";
}
output:
one
two
three
The loop terminates, at the "end" of the array.
foreach and arrays (2)
Using the indices

foreach $i (0 .. $#stuff) {
print "$stuff[$i] \n";
}
or only the range you want
foreach $i (0, 2 .. $#stuff) {
If the array is shorter than 2, it will stop.
print "$stuff[$i] \n";
}
interpolation of arrays to a string (1)
print will printout the values of 1 dimensional
print "@arr \n";
prints values with a single space between them
It doesn't matter what precedes or follows the
array, still prints the same
print @arr, "\n";
print the array with no space between

print "@2Darray";
prints the pointers to the arrays, instead of values
interpolation of arrays to a string (2)
$str = "@arr";
produces a string of the elements, separated by a
space.
$str = "@2Darray";
same as printing, the string has the pointers.
$str = "$2Darray[0]";
produces a string with the pointer to slice 0
$str = "@{$2Darray[0]}";
produces a string of values from the that section.
To get all the values into one string
foreach $i (0 .. $#2Darray) {
$str .= "@{$2Darray[$i]} ";
}
Input and arrays
Remember that <STDIN> reads until the end of
a line (same of file I/O)
Unlike c/c++ and most languages, perl reads
the entire line into a variable.
So $x = <STDIN>; #gets the whole line
chomp($x); #get rid of the end of line marker.

Now what?

We need to split that string up into useful parts.


split operator
using the split operator.
split(' ',$x);
splits up a string into parts. We want to split up
the string on the space and creates a list.
@stuff = split(' ',$x); #puts the list into the
array.
Now we have the input as would be expected.
The value it splits on is removed.
Example:
$x = "Hi there, 1";
@stuff = split(' ', $x);
$stuff[0] = "Hi", $stuff[1]="there,", $stuff[2]=1;
split (2)
Or a string can be split into scalar variables
($v1, $v2, $v3) = split(' ',$x);
$v1 ="Hi"; $v2="there,"; $v3=1;
Definition of split
( ) = split ( what to split on, variable);
split ' ', $x; works as well. Also () and the variable
are optional.
Be careful to use the correct " and '
@stuff = split('e, ', $x);
$stuff[0] = "Hi ther"; $stuff[1]=1;
split (3)
If you only wanted the second part
(undef,$v1) = split('e, ', $x);
$v1 = 1; undef says to throw it away.
splitting scalar and arrays
($v, @stuff) = split(' ',$x);
$v = "Hi", @stuff has the rest;

(@stuff, $v) = split(' ',$x);


$v = 1; @stuff has the first part.
join operator
join takes a list and creates a single string
string = join "string to be added between
parts", LIST

$str = join ' ',@stuff;


$str = "Hi there, 1";
$str = join "stuff", ("Buy", Now");
$str = "Buy stuff Now";
join operator (2)
Html example with join
Create a table with arrays in html
print "<table><tr><td>\n";
$str = join "</td><td>", @arrayofvalues;
print $str, "\n";
print "</td></tr></table>\n";
output:
<table><tr><td>
val</td><td>val</td><td>val
</td></tr></table>
Exercise 5
Write a script that reads a line of numbers.
From a file or STDIN
loop until you get to the end of the file
for STDIN on windows use control-z
for STDIN on UNIX use control-d
For each line
It should add them up all the values.
It should print:
sum = the sorted listed of numbers in descending order.
Q&A

You might also like