|
|
<!doctype html> |
|
|
<html> |
|
|
<head> |
|
|
<meta charset="utf-8"> |
|
|
<meta http-equiv="X-UA-Compatible" content="IE=edge"> |
|
|
<meta name="viewport" content="width=device-width, initial-scale=1"> |
|
|
<title>My Learning Website</title> |
|
|
<link href="/styles/styles.css" rel="stylesheet" type="text/css"> |
|
|
<link href="/programming/styles/styles.css" rel="stylesheet" type="text/css"> |
|
|
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries --> |
|
|
<!-- WARNING: Respond.js doesn't work if you view the page via file:// --> |
|
|
<!--[if lt IE 9]> |
|
|
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script> |
|
|
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> |
|
|
<![endif]--> |
|
|
</head> |
|
|
<body> |
|
|
|
|
|
<div class="banner"> |
|
|
<h1 class="courselink">Perl 5 Essential Traning</h1> |
|
|
<h2 class="lecturer">LinkedIn Learning : Bill Weinman</h2> |
|
|
<h2 class="episodetitle">Basic Syntax</h2> |
|
|
</div> |
|
|
|
|
|
<article> |
|
|
<h2 class="sectiontitle">Anatomy of a Perl Script</h2> |
|
|
<p>The code shown in figure 5 is a simple Hello World program.</p> |
|
|
<pre class="inset"> |
|
|
1. #!/usr/bin/perl |
|
|
2. ## hello.pl by Bill Weinman <http://bw.org/contact/> |
|
|
3. |
|
|
4. use 5.16.0; |
|
|
5. use warnings; |
|
|
6. |
|
|
7. my $var; |
|
|
8. say $var; |
|
|
9. say "Hello, World!";</pre> |
|
|
<p class="caption">Figure 5 - a simple Hello World program in Perl</p> |
|
|
<p>Note the shebang line which dictates how the program is run. When a script is opened in a shell, it looks at the first two characters to determine what type of file it is. If these two characters are a shebang (shell bang because the ! is sometimes called a bang and the line is read from the invoking shell), the rest of the line is checked to see which shell will run this script (eg, bash or perl).</p> |
|
|
<p>Not all operating systems use this convention. Windows, for example, would see the shebang as a comment and ignore it. Even if you don’t need it, if there is a chance that your script might run in a different environment, it's better to include it.</p> |
|
|
<p>The line</p> |
|
|
<p class="inset">use 5.18.10;</p> |
|
|
<p>specifies the version of Perl and 5.18.0 is a generally safe choice but I’m running my code on a Daxtra vm which has a slightly older version so this has been changed to</p> |
|
|
<p class="inset">use 5:16:3;</p> |
|
|
<p>Essentially, this specifies what Perl syntax should be used and I could have rounded down to 5.16.0 but the line can also be omitted as well.</p> |
|
|
<p class="inset">use warnings;</p> |
|
|
<p>This is self-explanatory and causes the interpreter to issue warnings for a variety of different potential problems such as unused or redefined variables and so on. It is not recommended that you omit this, but if you have already included a use statement with a version number, this automatically switches warnings on so you don't need both.</p> |
|
|
<p>Note that warnings are usually just that and will not stop execution.</p> |
|
|
<p>Unlike some programming languages, Perl doesn’t have block (or multiline) comments, just inline comments where everything after the # and to the end of the line is treated as a comment. Bear in mind, however, that sometimes conventions are used such as the shebang line which mean that a comment is not always just a comment!</p> |
|
|
<p>A more complex program is shown in figure 6 below.</p> |
|
|
<pre class="inset"> |
|
|
1. #!/usr/bin/perl |
|
|
2. ## countlines3.pl by Bill Weinman <http://bw.org/contact/> |
|
|
3. |
|
|
4. use 5.16.0; |
|
|
5. use warnings; |
|
|
6. use IO::File; |
|
|
7. |
|
|
8. main(@ARGV); |
|
|
9. |
|
|
10. ## entry point |
|
|
11. sub main |
|
|
12. { |
|
|
13. my $filename = shift || "linesfile.txt"; |
|
|
14. my $count = countlines( $filename ); |
|
|
15. say "There are $count lines in $filename"; |
|
|
16. } |
|
|
17. |
|
|
18. # countlines ( filename ) - count the lines in a file |
|
|
19. # returns the number of lines |
|
|
20. sub countlines |
|
|
21. { |
|
|
22. my $filename = shift; |
|
|
23. error("countlines: missing filename") unless $filename; |
|
|
24. |
|
|
25. # open the file |
|
|
26. my $fh = IO::File->new( $filename, "r" ) or |
|
|
27. error("Cannot open $filename ($!)\n"); |
|
|
28. |
|
|
29. # count the lines |
|
|
30. my $count = 0; |
|
|
31. $count++ while( $fh->getline ); |
|
|
32. |
|
|
33. $fh->close; |
|
|
34. |
|
|
35. # return the result |
|
|
36. return $count; |
|
|
37. } |
|
|
38. |
|
|
39. # error ( string ) - display an error message and exit |
|
|
40. sub error |
|
|
41. { |
|
|
42. my $e = shift || 'unkown error'; |
|
|
43. say "$0: $e"; |
|
|
44. exit 0; |
|
|
45. } </pre> |
|
|
<p class="caption">Figure 6 - the countlines3.pl program</p> |
|
|
<p>One point of interest is line 6 where we are reading in the IO::File module</p> |
|
|
<p class="inset">use IO::File;</p> |
|
|
<p>Perl uses a lot of modules which are either built in or part of a library such as CPAN. Here, we can see that we haven’t used a fully qualified name so this is a built-in module.</p> |
|
|
<h2 class="sectiontitle">Statements and Expressions</h2> |
|
|
<p>These overlap somewhat in Perl but in general, a statement is an instruction to the computer to do something and an expression is a value (or something that returns a value).</p> |
|
|
<p>Let’s look at line 13 from countlines3.pl</p> |
|
|
<p class="inset">$filename = shift || "linesfile.txt";</p> |
|
|
<p> "linesfile.txt" is an expression since it returns a value, namely itself</p> |
|
|
<p>shift is also an expression but it doesn’t return a literal value, as we saw earlier, it will return the parameter passed to the program</p> |
|
|
<p>The or expression returns a value so it is an expression. It will return the result of shift or the string literal.</p> |
|
|
<p>The assignment returns the value obtained from the or expression so it is also an expression. </p> |
|
|
<p>In addition, the assignment is a statement since it is instructing the computer to assign the result of an expression to the variable $filename. </p> |
|
|
<p>Note that the semi-colon is a separator, not a terminator so if you have a block of code, you don’t need to have a semi-colon at the end of the last line. </p> |
|
|
<p>If we look at the main function in countlines3.pl, for example</p> |
|
|
<pre class="inset"> |
|
|
1. sub main |
|
|
2. { |
|
|
3. my $filename = shift || "linesfile.txt"; |
|
|
4. my $count = countlines( $filename ); |
|
|
5. say "There are $count lines in $filename"; |
|
|
6. }</pre> |
|
|
<p>Here, we have a semi-colon at the end of each line but the third one, at the end of the say statement, is optional. If you omit it, the code will still run. </p> |
|
|
<p>Nevertheless, it is considered good practice to treat it as though it were a terminator and put it at the end of every line, even when not required because if you don’t and then you add another line to the function, you may forget that you have to put a separator at the end of the previous line. </p> |
|
|
<p>One final note on expressions, as we saw, an expression is something that returns a value, but it is the nature of Perl that almost everything returns a value so expressions are everywhere! </p> |
|
|
<h2 class="sectiontitle">Assignments</h2> |
|
|
<p>As well as straightforward assignments, Perl supports compound assignment operators (stolen from C) so you cam do things like</p> |
|
|
<p class="inset">$x += 110;</p> |
|
|
<p>or</p> |
|
|
<p class="inset">$y *= 7;</p> |
|
|
<p>You can also use increment operators (again, from C) </p> |
|
|
<p class="inset">$count++;</p> |
|
|
<p>You can also assign values to an array with a simple assignment such as</p> |
|
|
<p class="inset">my @array = (1, 2, 3);</p> |
|
|
<p>and we could print this out with something like</p> |
|
|
<p class="inset">@array;</p> |
|
|
<p>That works, but not very well since we are really just dumping the contents of the array to the screen without any formatting. If we want to print each element individually, we could do that with a for each loop such as</p> |
|
|
<p class="inset">say foreach @array;</p> |
|
|
<p>The syntax here may look a little strange but let’s just remind ourselves that almost everything in Perl returns a value. As a result, say is taking as input the output of the foreach loop and this is, for each element of the array, simply returning the element. The end result is that we are executing say with each element of the array individually. So, this is really just a Perl shorthand for what otherwise might be a loop that iterates through each element of the array, executing some code block which might contain the say statement. </p> |
|
|
<p>Another interesting feature in Perl is that you can assign an array to a scalar variable with an assignment statement such as</p> |
|
|
<p class="inset">my $count=@array;</p> |
|
|
<p>This will assign the size of the array to the variable. We can output this with a statement such as</p> |
|
|
<p class="inset">say "There are $count elements in the array.";</p> |
|
|
<p>We can also assign a list of values to a list of scalars with a statement such as</p> |
|
|
<p class="inset">my ($x, $y, $z) = (1, 2, 3);</p> |
|
|
<p>We can then treat each variable as separate from each other. For instance, we can display them with</p> |
|
|
<pre class="inset"> |
|
|
1. say $x; |
|
|
2. say $y; |
|
|
3. say $z;</pre> |
|
|
<h2 class="sectiontitle">Whitespace and Comments</h2> |
|
|
<p>Perl treats white space in source code in more or less the same way as any other language does. That is, the interpreter ignores it and its real purpose is to layout the code better to make it easier for a human to read. </p> |
|
|
<p>There are a couple of interesting points here relating to the interpolation of variable names inside a string. Let’s look back at a line of code from countlines3.pl.</p> |
|
|
<p class="inset">say "There are $count lines in $filename";</p> |
|
|
<p>We could take some of the spaces out of the string to give</p> |
|
|
<p class="inset">say "Thereare$count lines in $filename";</p> |
|
|
<p>This will still work but the string will be printed as shown so this would give the output as</p> |
|
|
<p class="inset">Thereare27 lines in stub</p> |
|
|
<p>So, this is not incorrect Perl but is probably incorrect formatting since it is likely that you would want your code to be a bit more readable than that! </p> |
|
|
<p>Note that we took out a space before the variable name, </p> |
|
|
<p class="inset">Thereare$count</p> |
|
|
<p>This is fine because the $ indicates the presence of a scalar variable and we can consider this the starting point for the variable name. The variable name is terminated with a space so if we delete the space after it</p> |
|
|
<p class="inset">say "Thereare$countlines in $filename";</p> |
|
|
<p>This will give an error because we can no longer extract the variable name. However, another option which doesn’t use a space to terminate the variable name (by terminate here, I really mean delimit or indicate the end of) is curly brackets. So we can have</p> |
|
|
<p class="inset">say "Thereare${count}lines in $filename";</p> |
|
|
<p>and that works fine as well. It does delimit the variable name so there is no ambiguity for the interpreter. However, since we have not put a space before or after the variable name, there will not be a space before or after it in the output so we need to be careful in this type of scenario to ensure the output is neatly formatted and readable. </p> |
|
|
<h2 class="sectiontitle">Blocks and Scope</h2> |
|
|
<p class="caption">Figure 7 shows the code got blocks.pl and we will use that to demonstrate both blocks and scope.</p> |
|
|
<pre class="inset"> |
|
|
1. #!/usr/bin/perl |
|
|
2. # blocks.pl by Bill Weinman <http://bw.org/contact/> |
|
|
3. |
|
|
4. use 5.16.0; |
|
|
5. use warnings; |
|
|
6. |
|
|
7. my $alpha = 'alpha'; |
|
|
8. my $beta = 'beta'; |
|
|
9. my $charlie = 'charlie'; |
|
|
10. |
|
|
11. func(); |
|
|
12. |
|
|
13. sub func { |
|
|
14. foreach my $x ( $alpha, $beta, $charlie ) { |
|
|
15. say $x; |
|
|
16. } |
|
|
17. } </pre> |
|
|
<p class="caption">Figure 7 - blocks.pl, used to demonstrate both blocks and scope</p> |
|
|
<p>The code in blocks.pl has two code blocks. The first is the function starting on line 13 and the second is the foreach loop inside that function. We also have three variables defined, all with the keyword my and this gives them scope within the innermost block of code where they are defined. In this case, they are defined in the file, but not within a code block within that file so they can be used anywhere (within the file, obviously). </p> |
|
|
<p>We can see that this code works find and as expected, it displays the value of each variable in turn. If we take out the my keyword for one or more variable, it just won’t work because we need to specify what type of variable (scalar, array or hash). </p> |
|
|
<p>Actually, just an aside, I think that it is probably meaningless to say that the keyword gives the variable scope since it could be argued that defining it in a specific place (as we did here, outside of any of the code blocks) is what gives it scope. It would probably be more correct to say that it defines the variable as scalar and leave it at that. </p> |
|
|
<p>Since scope is essentially part of the variable’s definition, we can define variables with the same name provided that they have different scope. This is demonstrated in the code shown in figure 8. </p> |
|
|
<pre class="inset"> |
|
|
1. #!/usr/bin/perl |
|
|
2. ## blocks.pl by Bill Weinman <http://bw.org/contact/> |
|
|
3. |
|
|
4. use 5.16.0; |
|
|
5. use warnings; |
|
|
6. |
|
|
7. my $alpha = 'alpha'; |
|
|
8. my $beta = 'beta'; |
|
|
9. my $charlie = 'charlie'; |
|
|
10. |
|
|
11. func(); |
|
|
12. |
|
|
13. sub func { |
|
|
14. my $beta="func-beta"; |
|
|
15. foreach my $x ( $alpha, $beta, $charlie ) { |
|
|
16. say $x; |
|
|
17. } |
|
|
18. } |
|
|
19. say $beta; </pre> |
|
|
<p class="caption">Figure 8 - blocks.pl with the scalar variable, $beta, defined twice with different scopes</p> |
|
|
<p>We have defined $beta on line 8 and again on line 14. The first of these has scope anywhere within this file whereas the second has scope within the func function only. When the func function executes, it will look within the block first for a definition of the variables which it won’t find. Bear in mind that we are using these variables inside the for loop. It will then look inside the next code block, that is the block that includes the loop in this case and that is the function. In the case of $beta, it will find a definition. For both $alpha and $charlie, it will not find a definition so it will look for a definition in the block that contains func which is the file and it will find the definitions there.</p> |
|
|
<p>There are a couple of points here. The first is that the variable definition that applies when a variable is used is the one that is most local to the call. So, inside the function, a variable defined there will take precedence over a definition outside of the function (in essence, the interpreter is searching for a definition from the inside out).</p> |
|
|
<p>Another point which is hopefully obvious is that a definition will only be found if it is either defined within the code block where it is used or within a code block that contains that block. That is, the for loop is inside the function which is inside the file so there are three blocks where we might potentially define the variable and these blocks have a hierarchical structure like so:</p> |
|
|
<pre class="inset"> |
|
|
• the file |
|
|
o the function |
|
|
the loop</pre> |
|
|
<p>Hence, we can call any of the variables inside the loop or, indeed, inside the function or elsewhere in the file if required.</p> |
|
|
<p>If we run the code shown in figure 8, the output will be</p> |
|
|
<pre class="inset"> |
|
|
1. izoom@localhost:perl5EssTraining $ perl ./blocks.pl |
|
|
2. alpha |
|
|
3. func-beta |
|
|
4. charlie |
|
|
5. beta </pre> |
|
|
<p class="caption">Figure 9 - the output from running the code shown in figure 8</p> |
|
|
<p>Notice that we are displaying the value of beta twice, on lines 3 and 5. The first of these, on line 3, results from the call inside the for loop and so it uses the definition in the function. The second, on line 5, is called from outside of the function where the variable $beta which has the value of “func-beta” does not have scope.</p> |
|
|
<p>If we didn’t have a definition of $beta outside the function, we would get an error. We do, and it was been assigned the value “beta”, so this is what we see in the output on line 5.</p> |
|
|
<p>Going back to the point I made about the my keyword and the fact that if you don’t include it when declaring a variable, you will get an error. This is actually because of the fact that we are using strict mode. We don’t have the use strict directive in any of the code examples, but when we specify the Perl version as in</p> |
|
|
<p class="inset">use 5.16.0;</p> |
|
|
<p>this automatically invokes strict mode so the effect is the same. If we comment out this line, we won’t see this error if we check the syntax of the script, but we still seem to get the error when we try to use the variable.</p> |
|
|
<p>From this, I would infer that declaring a variable without scope (that is, without the my keyword) means that you can’t use it within the file. I’m not sure if there is any situation where you could use a variable declared in this way so for now, I will simply assume that it is required.</p> |
|
|
<p>In any case, it is considered good practice to always use strict mode and if you do that, you will always get an error if you omit it.</p> |
|
|
<p>It is worth pointing out that if you use strict mode and you omit my from a variable assignment, you will get this error</p> |
|
|
<p class="inset">Global symbol "$var" requires explicit package name at hello.pl line 7.</p> |
|
|
<p>Unfortunately, the error message makes no sense in this context and it does not give any guidance as to how to fix the error. However, you will only ever see this error in a situation where you have forgotten to include the my keyword so you can interpret it as “missed my in variable declaration” and it should then be easy to fix the error.</p> |
|
|
<p>Referring back to the code in figure 5, we can omit the keyword so that the script looks like that shown in figure 10.</p> |
|
|
<pre class="inset"> |
|
|
1. #!/usr/bin/perl |
|
|
2. ## hello.pl by Bill Weinman <http://bw.org/contact/> |
|
|
3. |
|
|
4. use 5.16.0; |
|
|
5. use warnings; |
|
|
6. |
|
|
7. my $var; |
|
|
8. say $var; |
|
|
9. say "Hello, World!"; </pre> |
|
|
<p class="caption">Figure 10 - the code from figure 5 repeated with the my keyword omitted</p> |
|
|
<p>If we check the syntax, we will see an error here as follows:</p> |
|
|
<pre class="inset"> |
|
|
1. izoom@localhost:perl5EssTraining $ perl -c hello.pl |
|
|
2. Global symbol "$var" requires explicit package name at hello.pl line 7. |
|
|
3. Global symbol "$var" requires explicit package name at hello.pl line 8. |
|
|
4. hello.pl had compilation errors. </pre> |
|
|
<p>Note that we have two errors, one where the variable is declare and one where it is used.</p> |
|
|
<p>One final point to make is that if you try to use a variable and it is not defined for that scope, you will also see this same error message. For instance, if we go back to the code shown in figure 8 and comment out the definition of the $beta variable on line 8, this would be fine if we only call the variable in the loop. However, since we use the variable outside the loop and, indeed, outside the function, the definition inside the function is not in scope so we see the error as follows.</p> |
|
|
<pre class="inset"> |
|
|
1. izoom@localhost:perl5EssTraining $ perl ./blocks.pl |
|
|
2. Global symbol "$beta" requires explicit package name at ./blocks.pl line 19. |
|
|
3. Execution of ./blocks.pl aborted due to compilation errors. </pre> |
|
|
</article> |
|
|
|
|
|
<div class="btngroup"> |
|
|
<button class="button" onclick="window.location.href='quickstart.html';"> |
|
|
Previous Chapter - Quick Start |
|
|
</button> |
|
|
<button class="button" onclick="window.location.href='values.html';"> |
|
|
Next Chapter - Values and Variables |
|
|
</button> |
|
|
<button class="button" onclick="window.location.href='perl5essentialtraining.html'"> |
|
|
Course Contents |
|
|
</button> |
|
|
<button class="button" onclick="window.location.href='/programming/programming.html'"> |
|
|
Programming Page |
|
|
</button> |
|
|
<button class="button" onclick="window.location.href='/index.html'"> |
|
|
Home |
|
|
</button> |
|
|
</div> |
|
|
|
|
|
</body> |
|
|
</html> |