4 |
Basic Programing |
BUILT IN Functions -
We've already encountered our first function with print. Functions take inputs called parameters. In the case of print, it can be fed a string. It takes the string and sends it to stdout by default. Functions also have return values. Try this program.
#!/usr/bin/perl while($temp=<>){ $temp=$temp; $catch=print "TMP $temp"; print "Catch is $catch\n"; } |
~
What is the return value of print?
The fact that print interprets a parameter and sends it's interpretation to STDOUT is different from it's return value. All functions have return values. It's output to STDOUT is called a side effect. Sometimes we use functions for their side effects, other times we need their return values. Other times we need both.
Another function commonly used when working with STDIN is chomp. chomp removes certain chars from STDIN.
#!/usr/bin/perl while(<>){ print "BEFORE CHOMP ==> $_"; $ret = chomp $_; print "After CHOMP ==> $_"; } |
What does chomp do? It removes the line feed that is tacked onto the end of your strings as they are entered into $_. Sometimes it might be useful to have the line feed. Often it is in the way, and chomp removes it.
This program outlines most of the basic elements of a Perl program:
Variables:
A symbol that access data stored in RAM
Scalar Variables -
The basic storage construct in Perl. We have discussed that computers have fundamental data types that it can manipulate. These basic data types include Integers, Characters, and Floating Point Numbers, Computers also understand registry addresses and other more internal kinds of data. Perl scalar variables store an abstraction of they basic data types.
String for example are really array of chars and are not basic data types as understood by your computer. Perl, however, allows us to store an entire string in on scalar variable.
$myscalar = "my dog has fleas";
print $mystring;
Scalar variables can also store integers:
#!/usr/bin/perl $myint1 = 6; $myint2 = 4;$sum = $myint1 + $myint2; print " First INT is ====> $myint1\nSecond INT ==> $myint2\n"; print " The Sum of them is ==>$sum\n" ; |
Notice that the value is scalar $sum is not a string. The command print $sum would convert the contents of $sum to a string representation of the integer.
Try this program:
#!/usr/bin/perl $myint1 = 6;$myint2 = 4;$sum = $myint1 + $myint2; print $sum; #$sum is still an int $sum = $sum . "\n"; print $sum #print has been converted to a string ruben@ruben:/home/ruben/perl_course > chmod 744 file8 ruben@ruben:/home/ruben/perl_course > file8 1010 ruben@ruben:/home/ruben/perl_course > |
In this example Perl automatically converts the integer into the string '10'. The (.) operator concatenates the line return to $sum, and the entire value of the expression is returned back to $sum, replacing the old value. $sum is now a 3 char string "10\n";
Keywords Keywords instruct your program to do specific things. They can represent flow control instructions such as while, do or for. The can be logic statements like if or else. They can be commands to the parsing engine to bring in outside files for processing such as use or require.
Quotes
Perl has a complex system for quoting which will present many opportunities for debugging and security concerns. Perl has two systems for quoting. One is the common use of an expression in quotes such as:
$catch="My Dog has Fleas";
The second quoting method substitutes the default quote character. In this syntax the q character is a keyword.
q|My Dog Has Fleas|
or
q!My Dog has Fleas!;
The default quote marker can be substituted for with any non-alphanumeric character. Page 41 in the Camel book list the 7 kinds of quote
' |
q// |
String Literal |
" |
qq// |
String Literal with interpolation |
` |
qx// |
shell execution |
( ) |
qw// |
Word Quotes - Lists |
// |
m// |
Match |
s/// |
s/// |
Substitution |
y/// |
tr/// |
Translation |
The last two require the s/// kind of syntax and have no traditional quoting method.
Quotes, as we have seen, have the capacity to alter their content according to a set of rules. The simplest case is single quote. This process is called interpolation. q(My Dog Has Fleas) will only interpolate the selected quoting character. In this case the quoting character is the parenthesis. If we want to include a parenthesis into the string, we would have to escape out of it's special meaning as follows: q(My \(Dog|Cat\) Has Fleas) . If we want to include a backslash, again, we need to escape out of it with a blackslash. All other symbols in the string are printed as exactly presented in the input.
Backslash - As we saw early in this class with \n line feed escape sequence, is used to give an alternate meaning to the next character other than it's default meaning within the current context. In itself, it is a metacharacter. When used before other metacharacter, it escapes their special meaning and converts it to a plain syntax. In single quotes their are only 2 metacharacter, '(or the set quote char) and \. If we want to print these two characters, we need to escape out of them.
Double quotes allow for a much broader level of interpolation and can, therefor, introduce security issues in your programs. Double quotes, for example, resolve scalar variables and other data structures as we have yet to see such as arrays, hashes and dereferenced blocks.
#!/usr/bin/perl $string1 = q(My Dog Has Fleas); print $string1; print "_END\n"; $string2 = q(Mary's hat is red); print $string2; print "_END\n"; $string3 = 'Mary\'s hat is red'; print $string3; print "_END\n"; $string4 ='\\\''; print $string4; print "_END\n"; |
The following escape sequences are understood by the double quotes. They are listed on page 40 of the Camel Book.
\n |
New Line |
\r | Carriage Return |
\t |
Tab |
\f |
Form Feed |
\b |
Backspace |
\a |
Alarm |
\e |
<ESC> |
\033 |
Octal Sequence (Esc in this case) |
\x7f |
Hexidecimal Sequence (Delete in this case) |
\cC |
Control Sequences (Ctrl C in this case) |
\u |
Next char Uppercase |
\l |
Next Char lowercase |
\U |
All UPPERCASE |
\L |
All lowercase |
\Q |
Backslash all non-alphanumerics |
\E |
End \U \L \Q |
\$ or \@ |
Don't interpolate Scalars or Arrays |
Operators
Operators are keywords that combine with data to produce resulting return values. The most familiar operators are mathematical ones such as + - / * which do mathematical operations on two numeric values and return a numeric value.
Page 76 of the Camel book lists all of Perls operators and gives their associativity and precedence.
Precedence -
Precedence is what is know as the order of operation. When multiple operators are in a single expression, the resulting outcome usually differs depending on which operator is performed first. Precedence can be hand set with the parenthesis.
For example:
$total = 6 * 3 + 4 automatically interpreted as
$total =(6*3) + 4
with a result of 22. It is not ever automatically interpreted as
$total = 6*(3+4)
with the result of 42. The assignment operator, =, has a very low precedence because we usually want the assignment of an expression to a variable to be the last thing to done.
Associativity -
Associativity is the direction in which values are interpreted by the operator. The minus operator, - , for example interprets values in a sweep from left to right.
$total = 6 - 3;
results in a 3. If it sweeps from right to left, the value returned would be -3. Assoicativity is discussed like the wind. Just as a warm southerly wind blows from the south to the north, so does left associativity sweep from the left to the right.
Operators can be binary, unary or either tertiary. unary operators work on one value, binary 2 values and tertiary operators work on 3 values.
Here is a list of all the Perl operators. A full discussion of Perl operators is in the man perlop documentation which comes with Perl.
Associativity Operators
Left |
-> infix |
Nonassociative |
++ -- autoincrement |
Right |
** Powers |
Right |
! (reverse logic), ~(bitwise negation), \(reference), +(positive number), - (negative number) |
Left |
=~ (bind for matching) !~ (bind does not match) |
Left |
* (Multiply), /(divide), % (modulus), x (repetition) |
Left |
+(plus), -(minus), . (cancatonate) |
Left |
<< >> (binary left and right shift) |
Nonassociative |
File testing operators and unary Names operators (page 83 and 85 in the Camel Book) |
Nonassociative (appear as if left) |
<(less than), >(greater than), <= (less than or equal), >=(greater than or equal), lt (less than Strings), gt (Greater than strings), le (less than or equal strings), ge (greater than or equal strings) |
nonassociative |
== (numeric equal test), != (numeric not equal test), <=> (numeric comparison test), eq (string equal test), ne (string not equal test), cmp (string compare test) |
Left |
& (bitwise and) |
Left |
| (bitwise or), ^(bitwise Xor) |
Left |
Logical AND |
Left |
Logical OR |
nonassiative |
. (String cancatination) |
Right |
?: Tertiary (if else test) |
Right |
=(assignment), += (plus assignment), -=(minus assignment), *= (multiplication assignment), /= (division assignment), **=(exponent assignment, among others... |
Left |
, OR => (both comma operators) |
Nonassociative |
List operators |
Right |
not |
Left |
and |
Left |
xor , or |
We will look at this list of operators in detail a little later. Fortunately, most associativity and precedence in Perl is Human Species friendly, and we will be able to use many of these operators without a formal rundown of their exact usage until we get to section on Operators.
Functions:
Functions (as called Methods in Object Oriented Lingo), are of three types. The first type is the built in function such as print. Chapter 3 of the Camel Book has a comprehensive rundown of all Perls built in core functions. Further documentation is in man perlfunc. The second kind of function is user defined functions, also called subroutines. A third kind of function is a function called from an outside library such as DBI->connect(); These can seem to be built in, although they are generally user defined. You were just not the user who defined them.
All Functions take parameter, although those parameter don't have to be used. Functions have return values and side effects. Let us examine the built in function join.
join has the following definition:
join EXPR, LIST
Often we are at a disadvantage when looking at functions in Perl, because unlike other programming languages which have strong datatypes, most of our functions simply have an EXPRESSION as an argument. To understand the proper syntax for that expression, we need to look closely. In the case of join, it takes separate strings in the second parameter and joins them with the value in the expression. A list, like a scalar value, is a fundamental datatype in Perl. Generally, we can view a list as a collection of scalar values.
An example of join can be seen in the following program:
#!/usr/bin/perl -w $string1 = "The first major battle of the American Revolution was the Battle of Brooklyn."; $string2 = "It was also the largest battle of the Revolution."; $string3 = "You can find out more about this historic battle at http://www.brooklynonline.com"; print "$string1\n"; $thestory = join ' ', ($string1, $string2); print "$thestory\n"; $thestory = join "\n", ($thestory, $string3); print "$thestory\n"; JBSapphire:~/perl_course$ file10 The first major battle of the American Revolution was the Battle of Brooklyn. The first major battle of the American Revolution was the Battle of Brooklyn. It was also the largest battle of the Revolution. The first major battle of the American Revolution was the Battle of Brooklyn. It was also the largest battle of the Revolution. You can find out more about this historic battle at http://www.brooklynonline.com JBSapphire:~/perl_course$ |
The first join in this program joins two strings with a space as represented by the expression ' '. The second join concatenates the two strings using a line feed which is the result of the expression "\n". We need the double quotes in this case to interpolate the \n into a line feed character. The return value of join is the concatenated string. There is no side effect in this function.
join behaves very much like the dot (.) operator.
$thestory = join " ", ($string1, $string2);
is equivalent to
$thestory = $string1 . ' ' . $string2; This is true of many operators and functions in Perl. The line can often blur as to what exactly is a function, and what is an operator.
The opposite of join is split. split is defined as follows:
split /PATTERN/, EXPR, LIMIT
In the case of split, the first parameter or argument is a Unix styled (actually a Perl styled) regular expression, an expression whose value is searched through for the given pattern, and Limit which is the maximum number of splits the function will perform. In join and split, not all the parameters need to be always given to the function. In split, it is rare to see a LIMIT given. If the expression is left out in split, it will search the system variable $_.
Try this program:
#!/usr/bin/perl -w $string1 = "The first major battle of the American Revolution was the Battle of Brooklyn."; $string2 = "It was also the largest battle of the Revolution."; $string3 = "You can find out more about this historic battle at http://www.brooklynonline.com"; #print "$string1\n"; $thestory = join ' ', ($string1, $string2); #print "$thestory\n"; $thestory = join "\n", ($thestory, $string3); print "$thestory\n"; $line = _ x 80; print "$line\n"; ($garbage, $newstring1, $newstring3) = split /(.*\.) /s, $thestory; ($garbage, $newstring2, $newstring3) = split /(.*\.)\n/s, $newstring3; print "This is \$newstring1 ==> $newstring1\n"; print "This is \$newstring2 ==> $newstring2\n"; print "This is \$newstring3 ==> $newstring3\n"; |
This program shows more features of split and join. First, you will notice that split is the opposite of join. One of the attributes of split is a unique behavior in the pattern match. Although we have yet to cover pattern matching in detail, understand that normally split searches through the string it is binded to, and looks for delimiters in the form of a pattern. The pattern in this line:
($garbage, $newstring1,$newstring3) = split /(.*\.)\n/s, $thestory;
searches the string in $thestory for the character set of any number of characters that follow are followed by a period and a line feed. Normally a pattern stops it's search when it reaches the first line feed. We added \n to our string to permmit some text formatting. In order to get the pattern to match everything in $thestory, including the line feed chars, we add an 's' after the pattern - /(.*\)\n/s. Patterns by default match the first largest pattern in the string they can This behavior is called greedy. split normally discards the delimiters. It returns the tokens between the patterns that it matches. If one uses the parenthesis in the pattern, split saves this part of delimiter in it's return values.
Examining this line:
($garbage, $newstring1,$newstring3) = split /(.*\.)\n/s, $thestory;
split is looking at the string
The first major battle of the American Revolution was
the Battle of Brooklyn. It was also the largest battle of the Revolution.
You can find out more about this historic battle
at http://www.brooklynonline.com
which is displayed when we run the program. split invokes Perls pattern matching engine which starts at the first character (Capital T) and continues to search for the combination of characters ".\n" It finds this after the word Revolution. It now determines this that this entire token is the delimiter. Since there is nothing in front of the delimitator, split return to the first variable in the list ($garbage) a null string. Now split looks at the delimiter and sees that it has parenthesis around the expression (.*\.). As a result it stores next that part of the delimiter as $newstring1, which is everything but the line feed. The line feed is discarded. Split then looks for the delimiter again. Since this is a very large delimiter, it's not likely to find it again in $thestory. Once it determines that there are no more delimiters within $thestory, split stores the rest of the string in the third scalar variable inside of the list, $newstring2.
FLOW CONTROL FEATURES
All Perl programs begin performing instructions from top to bottom, starting with the first line and ending with the last line. We can interrupt this order by using flow control key words and constructs to allow code to repeat or perform only on a condition. At the heart of this capability is the Perl curly braces ({ }). With curly braces, we can package set lines of code to be triggers under specific circumstances. All curly braces have a return value, although the return value does not always have to be used for something. The return value does not have to be a string, integer or other common datatypes. It often needs to interpreted by your code in order to be useful. Starting here we will be talking about curly braces a lot throughout this document. They are a cornerstone to writing complex code, creating structured programs, and object oriented programs.
Curly braces usually have a higher precedence than other portions of a statement. They can represent a significant security risk in your program. We will be learning about these risks in future sections.
For now, let's concentration on the use of curly braces to create loops and conditional statements. We saw the curly braces used earlier in conjunction with the keyword while.
while(EXPR){
statement;
statement;
}
Notice that constructions with curly braces do not need a semicolon. The internal statements within the curly braces do require semicolons.
While evaluates the expression, and if true or not null, it then enters the curly braces and executes all the statements within. When the last statement is finished, it evaluates the expression again, and loops repeatedly into the braces until the expression in the parenthesis evaluates to false or null, with are equivalent in Perl.
The sisters of while are do and until.
#!/usr/bin/perl -w $tmp = ""; do{ print "Hello - let me fetch some input! $tmp\n"; }until(($tmp=<>) eq "\n"); print "No more input recieved\n"; |
The for and foreach, which are synonyms, constructs are similar to the while construct. If differs in that it expects a scalar followed by a list argument .
#!/usr/bin/perl for $keyword (qw(MY DOG HAS FLEAS)){ print "$keyword\n"; } ruben@sruben:/usr/local/apache/htdocs/perl_course=>./file13 MY DOG HAS FLEAS |
This would be exactly the same as:
#!/usr/bin/perl foreach($i=0;$i<10;$i++){ print "$i\n"; } |
For C programmers, for also takes the c programming construct:
#!/usr/bin/perl for($i=0;$i<10;$i++){ print "$i\n"; } |
Conditional Constructions can also be used in conjunction with curly braces. These a constructs which only perform blocks of code when some condition is met. Conditions, like the while, are evaluated to true or false.
#!/usr/bin/perl print "Enter a digit==>";$a = <>; chomp $a; print "Enter a digit==>"; $b = <>; chomp $b;if($a < $b){ print "$a is less than $b\n"; }else{ print "$b is less than of equal to $a\n"; } ruben@sruben:/usr/local/apache/htdocs/perl_course=>./file15 Enter a digit==>2 Enter a digit==>5 2 is less than 5 ruben@sruben:/usr/local/apache/htdocs/perl_course=> |
This last construction is so common, that we have the ternary operator to do this in short hand.
#!/usr/bin/perl print "Enter a digit==>"; $a = <>; chomp $a; print "Enter a digit==>"; $b = <>; chomp $b; if($a < $b){ print "$a is less than $b\n"; }else print "$b is less than of equal to $a\n"; $result = ($a<$b)?$a:$b; print "$result is Less\n" |
Perl provides another shorthand for quickie if statements:
#!/usr/bin/perl $love = "She loves me"; print "It is true!\n" if($love eq "She loves me"); print "It is sad.\n" if($love ne "She loves me"); $love = "Nope"; print "It is true!\n" if($love eq "She loves me"); print "It is sad.\n" if($love ne "She loves me"); |
If you can fit the condition on as one expression, your in good shape with this shortcut.
Within curly braces, a number of keywords can be used. last, next and redo can all be added within the block to perform a loop control task.
#!/usr/bin/perl while(1){ print $i++ ."\n"; last if($i == 10); } print "BLAAAST OFF!\n" ruben@sruben:/usr/local/apache/htdocs/perl_course=>./file17 0 1 2 3 4 5 6 7 8 9 BLAAAST OFF! ruben@sruben:/usr/local/apache/htdocs/perl_course=> |
Last ends the loop. Next short-circuits the loop.
This next little program uses next, last, a function, and uses a new datatypes to acquire system information called a hash. We will discussion hashes soon, along with arrays and lists. For now, we can just accept that every Perl program has a variety of environment variable that it inherits from the operating system and shell which we can access with the datatypes called $ENV{KEYNAME};
#!/usr/bin/perl print "";# $status = &getstatus; $i = 60; while($status = &getstatus){ print "$status\n"; next if($status ne "ALL SYSTEMS ARE GO"); $i--; print "$i\n"; last if $i == 0;}sub getstatus{ $stat = $ENV{countdown}; return $stat; } IN THE BOURN SHELLruben@ruben:/home/ruben/perl_course > countdown="ALL SYSTEMS ARE GO"; export countdown; ruben@ruben:/home/ruben/perl_course > file18 ALL SYSTEMS ARE GO 20 ALL SYSTEMS ARE GO 19 ALL SYSTEMS ARE GO 18 ALL SYSTEMS ARE GO 17 ALL SYSTEMS ARE GO 16 ALL SYSTEMS ARE GO 15 ALL SYSTEMS ARE GO 14 ALL SYSTEMS ARE GO 13 ALL SYSTEMS ARE GO 12 ALL SYSTEMS ARE GO 11 ALL SYSTEMS ARE GO 10 ALL SYSTEMS ARE GO 9 ALL SYSTEMS ARE GO 8 ALL SYSTEMS ARE GO 7 ALL SYSTEMS ARE GO 6 ALL SYSTEMS ARE GO 5 ALL SYSTEMS ARE GO 4 ALL SYSTEMS ARE GO 3 ALL SYSTEMS ARE GO 2 ALL SYSTEMS ARE GO 1 ALL SYSTEMS ARE GO 0 ruben@ruben:/home/ruben/perl_course > file18 TROUBLE WILL ROBINSON TROUBLE WILL ROBINSON TROUBLE WILL ROBINSON TROUBLE WILL ROBINSON TROUBLE WILL ROBINSON TROUBLE WILL ROBINSON TROUBLE WILL ROBINSON TROUBLE WILL ROBINSON TROUBLE WILL ROBINSON TROUBLE WILL ROBINSON TROUBLE WILL ROBINSON TROUBLE WILL ROBINSON TROUBLE WILL ROBINSON TROUBLE WILL ROBINSON TROUBLE WILL ROBINSON TROUBLE WILL ROBINSON TROUBLE WILL ROBINSON TROUBLE WILL ROBINSON TROUBLE WILL ROBINSON TROUBLE WILL ROBINSON TROUBLE WILL ROBINSON |
CTRL C end the program.
We set the variable in the shell countdown equal to the string that we want and then export it. When the program starts, it inherits the variable and performs accordingly.
The last loop control command is redo. redo is similar to next. The difference is that next starts the loop over from the while, re-evaluating the expression in the parenthesis. redo starts the loop over again after the opening curly brace, without re-evaluating the expression within the paranthesis.
redo is rarely used. When it is used, it is used normally with logic operators like the if keyword.
While and for loops can have a secondary loop using the keyword continue. This block is executed after the original loops exited. After evaluating the block, it restarts the original block again. In general, continue makes decoding your code, especially if you are using large loops, difficult to follow and is not good programming practice. But the continue feature is available if you have a compelling reason to use it.
LABELS - All block can have labels. These labels can be fed to the loop control keywords last,next and redo. When using nested loops these can be very helpful. They also play a good role in documentation. Nested loops are loops inside loops inside loops. Overuse of labels creates the same trouble of difficult to debug code as can continue. Used modestly, they can be effective programming tools. If you are overusing labels, chance are you are better off using functions and structured programming technique. Structured programming technique is the programming design where functions are used extensively to reduce the among of code in you main program. It also encourages the use of functions defined in external files in order to make debugging easier.
#!/usr/bin/perl $day = "Oct 12"; $lanchday = "Oct 12"; print "$day\n"; print "$lanchday\n"; $i = 60; MINUTES: while(1){ next MINUTES if $day ne $lanchday; last if !$i; print "$i minutes "; $j = 60; $i--; SECOND: while(1){ $j--; last SECOND if !$j; print "and $j seconds\n"; } } |
Curly braces can also be tagged as user defined functions, sometimes known as subroutines. All subroutines have a dual nature. They have a physical location in your code where they are defined. There you assign a symbol to a routine. Later that symbol is called within your program to run your routine. Let's look at an example of how this works.
#!/usr/bin/perl $i = 100; &count($i); #This is the call to the function under the symbol count print "We have finished\n"; sub count{ #define symbol count ($integer) = @_; COUNTDOWN: while($i){ print "$i\n"; $i--; } } |
This is an example of the classic Perl function. The keyword sub tells Perl to record the following block of code in memory to be referenced by the symbol count. When Perl sees &count, it looks for the subroutine and activates it. This is a form of call and response. Information is sent into the curly braces through the use of another system variable, this time @_. In this example, we send the information within $i into our function. We will explain how this is done exactly later, but for now, we should just note that we can call a function with parameters and that these parameters are accessed through @_ within the function definition. @_ acts as an array in the function. An array in Perl is a group of scalar variables. Just like all scalars are called with a $ symbol , all arrays are defined with an @ symbol. We will be looking closely at arrays, hashes and references soon.
The line ($integer) = @_; in the first line of count assigns the value of $i to the scalar $integer. ($integer) represents a list of scalars with one scalar variable. ($integer, $string) would represent a list of two scalars.The classic Perl syntax for a function call is using the & character to call the sub-routine. the ampestand symbol is usually optional. I encourage it's usage. If you define your function before it's use, you can ignore it the use of parenthesis as well in the callback. Functions can be declared with a simple
sub myfunct();
at the top of your program. Then it can be called as
my func param1 param2....
If you include the & then include the parenthesis. Functions can also be prototyped. We discuss prototyping when we discuss variables more closely..
Curly braces can be used in combination with loops, flow control keywords, labels and functions. But remember that they are their own construct and can be used alone. You find them almost everywhere, and they are core to Perl
#!/usr/bin/perl while(<>){ $input = $_; chomp($input); SWITCH:{ if ($input eq "a"){ &a; last SWITCH }; if ($input eq "b"){ &b; last SWITCH }; if ($input eq "c"){ &c; last SWITCH }; exit if ($input eq "quit"); print "You didn't enter a b or c\n"; }#CLOSE SWITCH }#CLOSE WHILE sub a{ print "You entered a\n"; } sub b{ print "You entered b\n"; } sub c{ print "You entered c\n"; } |
#!/usr/bin/perl $catch = ${ print "I am in curly braces\n"; $i = 10; while($i){ print "$i\n"; $i--; } $i=10; $b = \$i; }; print "This is the curly braces return value.. $catch\n"; |
In a sense, every Perl program is enclosed with curly braces, and so all all the symbols. We will discuss this when we cover object oriented design and packages.
FILE STREAMS:
The last basic component to a program concerns opening and closing data streams. When a Perl program starts, it has 3 data streams that are automatically opened for you. The symbols for these streams are STDIN, STDOUT and STDERR. We call these data stream symbols FILEHANDLES.
We have seen that the angle bracket operators can be used to access data streams.
while<>{
is the same as
while<STDIN>{
In addition, we have seen that print sends it output by default to STDOUT and the standard output device. These two statements are the same:
print STDOUT "My Dog Have Fleas\n";
print "My Dog has Fleas\n";
STDERR is retained for error message and is sent to the standard output device. Although STDERR and STDOUT both are sent by default tot the standard output device, these are two separate streams.
Try the following program:
#!/usr/bin/perl print STDOUT "This is to STDOUT\n"; print STDERR "This is to STDERR\n"; |
Now run it as follows:
bash$ file23 This is to STDOUT This is to STDERR bash$ file23 1> /dev/null This is to STDERR bash$ file23 2> /dev/null This is to STDOUT |
2> represent STDERR in the born shell.
1> represents STDOUT in the born shell.
1> send the STDOUT to unixes magic /dev/null device - ie: It's sent to nowhere.
Filehandles can be opened to more than just the standard input and output streams. We can open filehandles to the filesystem for reading, writing, or append. You can also pipe data to an external program or input data from an internal program.
open FILEHANDLE, "/home/ruben/testfile.txt"; |
Open for input |
open FILEHANDLE, "</home/ruben/testfile"; |
Open for input |
open FILEHANDLE, ">/home/ruben/testme" |
Open for output. Removes the original file if it exists. |
open FILEHANDLE, ">>/home/ruben/testme" |
appends output to the end of the file. |
open FILENHANDLE "|mail ruben wynn.com" |
pipe output to the mail program |
open FILEHANDLE, "ping www.yahoo.com|" |
Open a pipe for input from ping |
The open function has many specifications aside from these. For one thing, you can replace the path of your file with a variable. This is very useful when you have a list of files that you want to read from serially, or if you want to create temporary files. You can leave out the file path if you have defined it with a scalar with the same symbol as your FILEHANDLE. Open is described more fully on page 191 of the Camel book and in the man perlfunc documentation.
Standard programming practice is to check if a FILEHANDLE is opened successfully. The die function comes in very handy for this:
#!/usr/bin/perl $FILEOUT = "/home/ruben/database2"; $FILEIN = "/home/ruben/database"; open OUTGOING, ">$FILEIN" or die "$!"; $i = 0; while($i < 11){ print OUTGOING "$i\n"; $i++; } close(OUTGOING); open INGOING, "$FILEIN" or die "$!"; open OUTGOING, ">$FILEOUT" or die "$!"; while(<INGOING>){ $tmp = $_; chomp($tmp); print OUTGOING "$tmp\tone\n" if $tmp == 1; print OUTGOING "$tmp\ttwo\n" if $tmp == 2; print OUTGOING "$tmp\tthree\n" if $tmp == 3; print OUTGOING "$tmp\tfour\n" if $tmp == 4; print OUTGOING "$tmp\tfive\n" if $tmp == 5; print OUTGOING "$tmp\tsix\n" if $tmp == 6; print OUTGOING "$tmp\tseven\n" if $tmp == 7; print OUTGOING "$tmp\teight\n" if $tmp == 8; print OUTGOING "$tmp\tnine\n" if $tmp ==9 ; print OUTGOING "$tmp\tten\n" if $tmp == 10; print OUTGOING "$tmp\tzero\n" if $tmp == 0; } close(INGOING); close(OUTGOING); bash$ file24 bash$ cat /home/ruben/database 0 1 2 3 4 5 6 7 8 9 10 bash$ cat /home/ruben/database2 0 zero 1 one 2 two 3 three 4 four 5 five 6 six 7 seven 8 eight 9 nine 10 ten bash$ |