{"id":225,"date":"2020-08-18T19:23:47","date_gmt":"2020-08-18T20:23:47","guid":{"rendered":"http:\/\/www.linux-tutorial.info\/?page_id=77"},"modified":"2020-08-22T19:26:17","modified_gmt":"2020-08-22T20:26:17","slug":"this-is-the-page-title-toplevel-60","status":"publish","type":"page","link":"http:\/\/www.linux-tutorial.info\/?page_id=225","title":{"rendered":"Perl"},"content":{"rendered":"\n<title>Perl<\/title>\n<p>\n<font color=RED>\n<b>This section is old and incomplete, even as an introduction. Although it covers a number of different aspects\nof perl, this section really needs to be redone. Any volunteers?\n<\/b>\n<\/font>\n<p>\nIf you plan to do anything serious on the\nWeb, I suggest that you learn  perl. In\nfact, if you plan to do anything serious on your machine, then learning\nperl is also a good idea. Although not\navailable on a lot of commercial versions, perl is almost universally available with Linux.\n<\/p>\n<p>\nNow, I am not saying\nthat you shouldn&#8217;t learn sed, awk, and\nshell programming. Rather, I am saying that you should learn all four. Both\nsed and\nawk have been around for quite a while, so they are\ndeeply ingrained in the thinking of most system administrators. Although you\ncould easily find a shell script on the system that didn&#8217;t have elements of\nsed or\nawk in it, you would be very hard pressed to find a\nscript that had no <glossary>shell<\/glossary>\nprogramming in it. On the other hand, most of the\nscripts that process information from other programs use either\nsed or awk.\nTherefore, it is likely that you will eventually come across one or the other.\n<\/p>\n<p>\nperl is another matter altogether. None of the standard scripts have perl\n in them. This does not say anything about the relative value of\nperl, but rather the relative\navailability of it. Because it can be expected that\nawk and sed\nare available, it makes sense that they are commonly used.\nperl may not be on your machine and including it in a\nsystem shell script might cause trouble.\n<\/p>\n<p>\nIn this section, I am going to talk about the basics of perl. We&#8217;ll go\nthrough the mechanics of creating perl scripts and the syntax of the perl\nlanguage. There are many good books on perl, so I would direct you to them to\nget into the nitty-gritty. Here we are just going to cover the basics. Later on, we&#8217;ll address\nsome of the issues involved with making perl scripts to use on your Web site.\n<\/p>\n<p>\nOne aspect of perl that I like is that it contains the best of everything. It has aspects\nof C, <glossary>shell<\/glossary>, awk,\nsed and many other things.\nperl is also free. The source code is readily\navailable and the versions that I have came with configuration scripts that\ndetermined the type of system I had and set up the make-files accordingly. Aside\nfrom Linux, I was able to <glossary>compile<\/glossary>\nthe exact same source on my Sun Solaris workstation. Needless to say, the scripts\nthat I write at home run just as well at work.\n<\/p>\n<p>\nI am going to make assumptions as to what level of programming\nbackground you have. If you read and understood the sections on\nsed, awk, and\nthe <glossary>shell<\/glossary>,\n then you should be ready for what comes next. In this section, I am\ngoing to jump right in. I am not going to amaze you with demonstrations of how\nperl can do <glossary>I\/O<\/glossary>,\n as that&#8217;s what we are\nusing it for in the first place. Instead, I am going to assume that you want to\ndo <glossary>I\/O<\/glossary>\nand jump right into how to do it.\n<\/p>\n<p>\nLets create a shell script\ncalled hello.pl. The\npl extension has no real meaning, although I have\nseen many places where it is always used as an extension. It is more or less\nconventional to do this, just as text files traditionally have the extension\n.txt, <glossary>shell<\/glossary>\nscripts end in .sh, etc.\n<\/p>\n<p>\nWe&#8217;ll start off with the traditional\n<\/p>\n<p>\nprint &#8220;Hello, World!\n&#8220;;<\/p>\n<p>\nThis shell script\nconsists of a single perl statement, whose purpose is to output the text\ninside\nthe <glossary>double-quotes<\/glossary>.\n Each statement in perl is followed  by a semi-colon. Here, we\nare using the perl print function to output the literal string &#8220;Hello,\nWorld!\n&#8221; (including the trailing new line). Although we don&#8217;t see it, there\nis the implied file handle to <glossary>stdout<\/glossary>.\n The equivalent command with the explicit\nreference would be\n<\/p>\n<p>\nprint STDOUT &#8220;Hello,\nWorld!\n&#8220;;<\/p>\n<p>\nAlong with\nSTDOUT, perl\nhas the default file handlers STDIN and\nSTDERR. Here is a quick script that\ndemonstrates all three as well as introduces a couple of familiar programming\nconstructs:<\/p>\n<p>\nwhile\n(&lt;STDIN&gt;)<\/p>\n<p>{<\/p>\n<p>&#9;if ( $_ eq  &#8221;\n&#8221; )\n<\/p>\n<p>&#9;{<\/p>\n<p>&#9;&#9;print STDERR &#8220;Error:\n&#8220;;<\/p>\n<p>&#9;} else\n{<\/p>\n<p>&#9;&#9;print STDOUT &#8220;Input: $_\n&#8220;;<\/p>\n<p>&#9;}<\/p>\n<p>}<\/p>\n<p>\nFunctioning the same as in C and most\nshells, the while line at the top says that as long as  there is something\ncoming from STDIN, do the loop. Here we have the special format (&lt;STDIN&gt;),\nwhich tells perl where to get input. If we wanted, we could use a file handle\nother than STDIN. However, we&#8217;ll get to that in a little bit.\n<\/p>\n<p>\nOne thing\nthat you need to watch out for is that you must include blocks of statements\n(such as after while or if statements) inside the curly braces ({}). This is\ndifferent from the way you do it in C, where a single line can follow while or\nif. For example, this statement is not valid in perl:\n<\/p>\n<p>\nwhile\n( $a &lt; $b )<\/p>\n<p>&#9;$a++;<\/p>\n<p>\nYou would need to write\nit something like this:<\/p>\n<p>\nwhile ( $a &lt; $b )\n{<\/p>\n<p>&#9;$a++;<\/p>\n<p>}<\/p>\n<p>\nInside the\nwhile loop, we get to an\nif statement. We compare the value of the special\nvariable $_ to see if it is empty. The\nvariable $_ serves several functions. In\nthis case, it represents the line we are reading from\nSTDIN. In other cases, it represents the pattern\nspace, as in sed. If the latter is true,\nthen just the Enter key was pressed. If\nthe line we just read in is equal to the newline character (just a blank line),\nwe use the print function, which has the syntax\n<\/p>\n<p>\nprint\n[filehandler] &#8220;text_to_print&#8221;;<\/p>\n<p>\nIn the first case,\nfilehandler is <glossary>stderr<\/glossary>\nand in the second case <glossary>stdout<\/glossary>\nis the filehandler. In each\ncase, we could have left out the filehandler and the output would go to stout.\n<\/p>\n<p>\nEach time we print a line, we need  to include a newline (\n) ourselves.\n<\/p>\n<p>\nWe can format the print line in different ways. In the second print line,\nwhere the input is not a blank line, we can print &#8220;Input: &#8221; before we\nprint the line just input. Although this is a very simple way of outputting\nlines, it gets the job done. More complex formatting is possible with the perl\nprintf function. Like its counterpart in C or awk, you can come up with some\nvery elaborate outputs. We&#8217;ll get into more details later.\n<\/p>\n<p>\nOne\nmore useful function for processing lines of input is\nsplit. The split\n function is used to, as its name implies, to split a line based on a\nfield separator that you define. Say, for example, a space. The line is then\nstored in an array as individual elements.  So, in our example, if we wanted to\ninput multiple words and have them parsed correctly, we could change the script\nto look like this:\n<\/p>\n<p>\nwhile\n(&lt;STDIN&gt;)<\/p>\n<p>{<\/p>\n<p>@field = split( ,$_);<\/p>\n<p>\nif ( $_ eq\n&#8221;\n&#8221; )\n<\/p>\n<p>{<\/p>\n<p>\nprint STDERR &#8220;Error:\n&#8220;;<\/p>\n<p>} else\n{<\/p>\n<p>\nprint STDOUT &#8220;$_\n&#8220;;<\/p>\n<p>\nprint $field[0];<\/p>\n<p>\nprint\n$field[1];<\/p>\n<p>\nprint $field[2];<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>\nThe\nsplit function has the\nsyntax\n<\/p>\n<p>\nsplit(pattern,line);<\/p>\n<p>\nwhere pattern is our field\nseparator and line is the input line. So\nour line\n<\/p>\n<p>@field = split( ,$_);<\/p>\n<p>\nsays to\nsplit the line we just read in (stored in $_) and use a space ( ) as the field\nseparator. Each field is then placed into an element of the array field. The @\nis needed in front of the <glossary>variable<\/glossary>\nfield to indicate that it&#8217;s an array. In perl,\nthere are several types of variables. The first kind we have already met before.\nThe special <glossary>variable<\/glossary>\n$_ is an example of a scalar variable. Each scalar variable\nis preceded by a dollar sign ($) and can contain a single value, whether a\ncharacter string or a number. How does perl tell the difference? It depends on\nthe context. perl will behave correctly by looking at what you tell it to do\nwith the <glossary>variable<\/glossary>.\n Other examples of scalars are\n<\/p>\n<p>$name =\n&#8220;jimmo&#8221;;<\/p>\n<p>$initial =\nj;<\/p>\n<p>$answertolifetheuniverseandeverything = 42;<\/p>\n<p>\nAnother kind\nof <glossary>variable<\/glossary>\nis an array, as we mentioned before. If we precede a variable with\n{3f0b0cf5c640d99e599990c4a720721a04ec3a009b1323dd81fc335ceb655a63}, we have an array. But don&#8217;t we have an array with @? Yes, so whats the\ndifference? The difference is that arrays, starting with the @, are referenced\nby numbers, while those starting with the {3f0b0cf5c640d99e599990c4a720721a04ec3a009b1323dd81fc335ceb655a63} are referenced by a string. We&#8217;ll get\nto how that works as we move along.\n<\/p>\n<p>\nIn our example, we are using the\nsplit function to fill up the array @field. This array will be referenced by\nnumber. We see the way it is referenced in the three print statements toward the\nend of the script.\n<\/p>\n<p>\nIf our input line had a different <glossary>field separator<\/glossary>\n(for\nexample, {3f0b0cf5c640d99e599990c4a720721a04ec3a009b1323dd81fc335ceb655a63}), the line might look like this:\n<\/p>\n<p>@field =\nsplit({3f0b0cf5c640d99e599990c4a720721a04ec3a009b1323dd81fc335ceb655a63},$_);<\/p>\n<p>\nIn this example, we are outputting the first three\nwords that are input. But what if there are more words? Obviously we just add\nmore print statements. What if there are fewer words? Now we run into problems.\nIn fact, we run into problems when adding more print statements. The question\nis, where do we stop? Do we set a limit on the number of words that can be\ninput? Well, we can avoid all of these problems by letting the system count for\nus. Changing the script a little, we get\n<\/p>\n<p>\nwhile\n(&lt;STDIN&gt;)<\/p>\n<p>{<\/p>\n<p>@field = split( ,$_);<\/p>\n<p>\nif ( $_ eq\n&#8221;\n&#8221; )\n<\/p>\n<p>{<\/p>\n<p>\nprint STDERR &#8220;Error:\n&#8220;;<\/p>\n<p>} else\n{<\/p>\n<p>\nforeach $word (@field){<\/p>\n<p>&#9;print\n$word,&#8221;\n&#8220;;<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>\nIn this\nexample, we introduce the foreach\nconstruct. This has the same behavior as a for\n loop. In fact, in perl,\nfor and\nforeach are interchangeable, provided you have the\nright syntax. In this case, the syntax is\n<\/p>\n<p>\nforeach\n$variable (@array)<\/p>\n<p>\nwhere $variable is our loop <glossary>variable<\/glossary>\nand @array is the name of the array. When the script is\nrun, @array is expanded to its\ncomponents. So, if we had input four fruits, our line might have looked like\nthis:<\/p>\n<p>\nforeach $word(apple,bananna,cherry,orange);<\/p>\n<p>\nBecause I don&#8217;t know how many elements there are in the array field,\nforeach comes in handy. In this example, every word\nseparated by a space will be printed on a line by itself, like\nthis:<\/p>\n<p>\nperl script.pl\n<\/p>\n<p>\none two\nthree\n<\/p>\n<p>\none\n<\/p>\n<p>\ntwo\n<\/p>\n<p>\nthree\n<\/p>\n<p>^D\n<\/p>\n<p>\nOur next enhancement is to change the <glossary>field separator<\/glossary>.\nThis time we&#8217;ll use an ampersand (&amp;) instead. The\nsplit line now looks like this:\n<\/p>\n<p>@field =\nsplit(&amp;,$_);<\/p>\n<p>\nWhen we run the script again with the\nsame input, what we get is a bit\n<\/p>\n<p>\ndifferent:<\/p>\n<p>#\nperl script.pl\n<\/p>\n<p>\none two three\n<\/p>\n<p>\none two three\n<\/p>\n<p>\nThe reason why we get the output on one line is because the space is\nno longer a <glossary>field separator<\/glossary>.\n If we run it again, this time using\n&amp;, we get something different:<\/p>\n<p># perl\nscript.pl\n<\/p>\n<p>\none&amp;two&amp;three\n<\/p>\n<p>\none\n<\/p>\n<p>\ntwo\n<\/p>\n<p>\nthree\n<\/p>\n<p>\nThis time, the three words were recognized as separate fields.\n<\/p>\n<p>\nAlthough it doesn&#8217;t seem too likely that you would be inputting data like\nthis from the keyboard, it is conceivable that you might want to read a file\nthat has data stored like this. To make things easy, I have provided a file that\nrepresents a simple database of books. Each line is a record and represents a\nsingle book, with the fields separated by {3f0b0cf5c640d99e599990c4a720721a04ec3a009b1323dd81fc335ceb655a63}.\n<\/p>\n<p>\nTo be able to read from a\nfile, we must create a file handle. To do this, we add a line and change the\nwhile statement so it looks like this:\n<\/p>\n<p>\nopen (\nINFILE,&#8221;&lt; bookdata.txt&#8221;);<\/p>\n<p>\nwhile\n(&lt;INFILE&gt;)<\/p>\n<p>\nThe syntax of the\nopen function is\n<\/p>\n<p>\nopen(file_handle,openwhat_&amp;_how);<\/p>\n<p>\nThe way we open a\nfile depends on the way we want to read it. Here, we use standard shell\nredirection symbols to indicate how we want to read the specified file. In our\nexample, we indicate <glossary>redirection<\/glossary>\n<i>from<\/i> the file bookdata.txt. This says we\nwant to read <i>from<\/i> the file. If we wanted to open the file for writing,\nthe line would look like this:\n<\/p>\n<p>\nopen ( INFILE,&#8221;&gt;\nbookdata.txt&#8221;);<\/p>\n<p>\nIf we wanted to append to the file, we could\nchange the redirections so the line would look like this:<\/p>\n<p>\nopen ( INFILE,&#8221;&gt;&gt;\nbookdata.txt&#8221;);<\/p>\n<p>\nRemember I said that we use standard\nredirection symbols. This also includes the <glossary>pipe<\/glossary>\nsymbol. As the need presents\nitself, your perl script can open a <glossary>pipe<\/glossary>\nfor either reading or writing. Assuming\nthat we want to open a <glossary>pipe<\/glossary>\nfor writing that sends the output through sort, the\nline might look like this:\n<\/p>\n<p>\nopen ( INFILE,&#8221;| sort\n&#8220;);<\/p>\n<p>\nRemember that this would work the same as\nfrom the <glossary>command line<\/glossary>.\n Therefore, the output is not being written to a file; it\nis just being piped through sort.\nHowever, we could redirect the output of sort\n, if we wanted. For example:<\/p>\n<p>\nopen (\nINFILE,&#8221;| sort &gt; output_file&#8221;);<\/p>\n<p>\nThis\nopens the file output_file for writing,\nbut the output is first piped through sort\n. In our example, we are opening the file\nbookdata.txt for reading. The\nwhile loop continues through and outputs each line\nread. However, instead of being on a single line, the individual fields\n(separated by &amp;) are output on a\nseparate line.\n<\/p>\n<p>\nWe can now take this one step further. Lets now assume\nthat a couple of the fields are actually composed of subfields. These subfields\nare separated by a plus sign (+). We now\nwant to break up every field containing +\ninto its individual subfields.\n<\/p>\n<p>\nAs you have probably guessed, we\nuse the split command again. This time,\nwe use a different <glossary>variable<\/glossary>\nand instead of reading out of the input line\n($_), we read out of the string\n$field. Therefore, the line would look\nlike this:\n<\/p>\n<p>@subfield =\nsplit(\\+,$field);<\/p>\n<p>\nAside from changing the search\npattern, I added the back slash (\\)\nbecause + is used in the search pattern\nto represent one or more occurrences of the preceding character. If we don&#8217;t\nescape it, we generate an error. The whole script now looks like\nthis:<\/p>\n<p>\nopen(INFILE,&#8221;&lt;bookdata.txt&#8221;);<\/p>\n<p>\nwhile\n(&lt;INFILE&gt;)<\/p>\n<p>{<\/p>\n<p>@data = split(&amp;,$_);<\/p>\n<p>\nif ( $_ eq\n&#8221;\n&#8221; )\n<\/p>\n<p>{<\/p>\n<p>\nprint STDERR &#8220;Error:\n&#8220;;<\/p>\n<p>} else\n{<\/p>\n<p>\nforeach $field (@data){<\/p>\n<p>&#9;@subfield =\nsplit(\\+,$field);<\/p>\n<p>&#9;foreach $word (@subfield){<\/p>\n<p>&#9;&#9;print\n$word,&#8221;\n&#8220;;<\/p>\n<p>&#9;&#9;}<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>\nIf we wanted, we could have written the script to split the incoming\nlines at both &amp; and\n+. This would have given us a\nsplit line that looked like this:<\/p>\n<p>@data = split([&amp;\\+],$_);<\/p>\n<p>\nThe reason for\nwriting the script like we did was that it was easier to separate subfields and\nstill maintain their relationships. Note that the search pattern used here could\nhave been any <glossary>regular expression<\/glossary>.\n For example, we could have split the strings\nevery place there was the pattern Di\nfollowed by e,\ng, or r, but\n<i>not<\/i> if it was followed by i. The\nregular expression would be\n<\/p>\n<p>\nDi[reg][^i]<\/p>\n<p>\nso the split function would\nbe:<\/p>\n<p>@data = split(Di[reg][^i],$_);<\/p>\n<p>\nAt this point, we can read in lines from an <glossary>ASCII<\/glossary>\nfile, separate the\nlines based on  what we have defined as fields, and then output each line.\nHowever, the lines don&#8217;t look very interesting. All we are seeing is the content\nof each field and do not know what each field represents. Let&#8217;s change the\nscript once again. This time we will make the output show us the field names as\nwell as their content.\n<\/p>\n<p>\nLets change the script so that we have control\nover where the fields end up. We still use the\nsplit statement to extract individual fields from the\ninput string. This is not necessary because we can do it all in one step, but I\nam doing it this way to demonstrate the different constructs and to reiterate\nthat in perl, there is always more than\none way do to something. So, we end up with the following script:\n<\/p>\n<p>\nopen(INFILE,&#8221;&lt;\nbookdata.txt&#8221;);<\/p>\n<p>\nwhile (&lt;INFILE&gt;)<\/p>\n<p>{<\/p>\n<p>@data =\nsplit(&amp;,$_);<\/p>\n<p>\nif ( $_ eq  &#8221;\n&#8221; )\n<\/p>\n<p>{<\/p>\n<p>&#9;print\nSTDERR &#8220;Error:\n&#8220;;<\/p>\n<p>} else {<\/p>\n<p>$fields = 0;<\/p>\n<p>\nforeach\n$field (@data){<\/p>\n<p>$fieldarray[$fields] = $field;<\/p>\n<p>\nprint\n$fieldarray[$fields++],&#8221; &#8220;;<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>}\n<\/p>\n<p>\nEach time\nwe read a line, we first split it into the array @data, which is then copied\ninto the fields array. Note that there is no new line in the print statement, so\neach field will be printed with just a space and the newline read at the end of\neach input line will then be output. Each time through the loop, we reset our\ncounter (the <glossary>variable<\/glossary>\n$fields) to 0.\n<\/p>\n<p>\nAlthough the array is re-filled\nevery time through the loop and we lose the previous values, we could assign the\nvalues to specific variables.\n<\/p>\n<p>\nLets now  make the output a little more\nattractive by outputting the field headings first. To make things simpler, lets\nlabel the fields as follows\n<\/p>\n<p>\ntitle, author, publisher, char0, char1, char2,\nchar3, char4, char5<\/p>\n<p>\nwhere\nchar0-char5\nare simply characteristics of a book. We need a handful of\nif statements to make the assignment, which look like\nthis:<\/p>\n<p>\nforeach $field (@data){<\/p>\n<p>\nif  (\n$fields = = 0 ){<\/p>\n<p>\nprint &#8220;Title: &#8220;,$field;<\/p>\n<p>}<\/p>\n<p>\nif  (\n$fields = = 1 ){<\/p>\n<p>\nprint &#8220;Author:\n&#8220;,$field;<\/p>\n<p>}<\/p>\n<p>*<\/p>\n<p>*<\/p>\n<p>*<\/p>\n<p>\nif  ( $fields = = 8\n){<\/p>\n<p> &#9;print &#8220;Char 5: &#8220;,$field;<\/p>\n<p>}<\/p>\n<p>\nHere, too, we\nwould be losing the value of each <glossary>variable<\/glossary>\nevery time through the loop as they\nget overwritten. Lets just assume we only want to save this information from the\nfirst line (our reasoning will become clear in a minute). First we need a\ncounter to keep track of what line we are on and an if statement to enter the\nblock where we make the assignment. Rather than a print statement, we change the\nline to an assignment, so it might look like this:<\/p>\n<p>$title =\n$field;<\/p>\n<p>\nWhen we read subsequent lines, we can output headers\nfor each of the fields. We do this by having another set of\nif statements that output the <glossary>header<\/glossary>\nand then the\nvalue, which is based on its position.\n<\/p>\n<p>\nActually, there is a way\nof doing things a little more efficiently. When we read the first line, we can\nassign the values to variables on a single line.  Instead of the line\n<\/p>\n<p>\nforeach $field (@data) {<\/p>\n<p>\nwe add the\nif statement to check if this is the\nfirst line. Then we add the line\n<\/p>\n<p>($field0,$field1,$field2,$field3,$field4,$field5,$field6,$field7,$field8)=<\/p>\n<p>&#9;split(&amp;,$_);<\/p>\n<p>\nRather than assigning values to\nelements in an array, we are assigning them to specific variables. (Note that if\nthere are more fields generated by the split command than we specified variables\nfor, the remaining fields are ignored.) The other advantage of this is that we\nsaved ourselves a lot of space. We could also call these $field1, $field2, etc.,\nthereby making the field names a little more generic. We could also modify the\nsplit line so that instead of several separate variables, we have them in a\nsingle array called field and we could use the number as the offset into the\narray. Therefore, the first field would be referenced like this:\n<\/p>\n<p>$field[0]<\/p>\n<p>\nThe split command for this would\nlook like this\n<\/p>\n<p>@field=split(&amp;,$_);<\/p>\n<p>\nwhich looks like something we\nalready had. It is. This is just another example of the fact that there are\nalways several different ways of doing things in perl.\n<\/p>\n<p>\nAt this point, we\nstill need the series of if statements inside of the foreach loop to print out\nthe line. However, that seems like a lot of wasted space. Instead, I will\nintroduce the concept of an associated list. An associated list is just like any\nother list, except that you reference the elements by a label rather than a\nnumber.\n<\/p>\n<p>\nAnother difference is that associated arrays, also\nreferred to as associated lists, are always an even length. This is because\nelements come in pairs: label and value. For example, we have:<\/p>\n<p>{3f0b0cf5c640d99e599990c4a720721a04ec3a009b1323dd81fc335ceb655a63}list= (name,James Mohr, <glossary>logname<\/glossary>,\njimmo,\ndepartment,IS);<\/p>\n<p>\nNote that instead of $ or @ to indicate that this\nis an array, we use {3f0b0cf5c640d99e599990c4a720721a04ec3a009b1323dd81fc335ceb655a63}. This specifies that this is an associative array, so we\ncan refer to the value by label; however, when we finally reference the value,\nwe use $. To print out the name, the line would look like this:\n<\/p>\n<p>\nprint &#8220;Name:&#8221;,$list{name};<\/p>\n<p>\nAlso, the brackets\nwe use are different. Here we use curly braces ({}) instead of square brackets\n([]).\n<\/p>\n<p>\nThe introduction of the associate array allows us to define field\nlabels within the data itself and access the values using these labels. As I\nmentioned, the first line of the data file containing the field labels. We can\nuse these labels to reference the values. Lets look at the program itself:\n<\/p>\n<p>\nopen(INFILE,&#8221;&lt;\nbookdata.txt&#8221;);<\/p>\n<p>$lines=0;<\/p>\n<p>\nwhile\n(&lt;INFILE&gt;)<\/p>\n<p>{<\/p>\n<p>\nchop;<\/p>\n<p>@data = split(&amp;,$_);<\/p>\n<p>\nif (\n$lines == 0 )<\/p>\n<p>{<\/p>\n<p>&#9;@headlist=split(&amp;,$_);<\/p>\n<p>&#9;foreach\n$field (0..@headlist-1){<\/p>\n<p>&#9;&#9;{3f0b0cf5c640d99e599990c4a720721a04ec3a009b1323dd81fc335ceb655a63}headers = ( $headlist[$field],\n);<\/p>\n<p>&#9;}<\/p>\n<p>$lines++;<\/p>\n<p>} else {<\/p>\n<p>&#9;foreach $field (0..@data-1){<\/p>\n<p>&#9;$headers{$headlist[$field]}=@data[$field];<\/p>\n<p>&#9;print $headlist[$field],&#8221;: &#8220;, $headers{$headlist[$field]},&#8221;\n&#8220;;\n<\/p>\n<p>&#9;}<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>\nAt the beginning of the script, we added the\nchop function, which &#8220;chops&#8221; off the last character of a list or\nvariable and returns that character. If you  don&#8217;t mention the list or <glossary>variable<\/glossary>,\nchop affects the $_ <glossary>variable<\/glossary>.\n This  function is useful to chop off the newline\ncharacter that gets read in. The next change is that we removed the block that\nchecked for blank lines and generated an error.\n<\/p>\n<p>\nThe first time  we read a\nline, we entered the appropriate block. Here, we just read in the line\ncontaining the field labels and we put each entry into the array headlist via\nthe split function. The foreach loop also added some new elements:\n<\/p>\n<p>&#9;foreach $field (0..@headlist-1){<\/p>\n<p>&#9;&#9;{3f0b0cf5c640d99e599990c4a720721a04ec3a009b1323dd81fc335ceb655a63}headers = (\n$headlist[$field], );<\/p>\n<p>&#9;}<\/p>\n<p>\nThe first addition is the element (0..\n@headlist-1). Two numbers separated by two dots indicate a range. We can use\n@headlist as a <glossary>variable<\/glossary>\nto indicate how many elements are in the array headlist.\nThis returns a human number, not a computer number (one that starts at 0).\nBecause I chose to access all my variables starting with 0, I needed to subtract\n1 from the value of @headlist. There are nine elements per line in the file\nbookdata.txt; therefore, their range is 0..9-1.\n<\/p>\n<p>\nHowever, we don&#8217;t need to\nknow that! In fact, we don&#8217;t even know how many elements there are to make use of\nthis functionality. The system knows how many elements it read in, so we don&#8217;t\nhave to. We just use @headlist-1 (or whatever).\n<\/p>\n<p>\nThe next line fills in\nthe elements of our associative array:\n<\/p>\n<p>{3f0b0cf5c640d99e599990c4a720721a04ec3a009b1323dd81fc335ceb655a63}headers = (\n$headlist[$field], );<\/p>\n<p>\nHowever, we are only filling in the labels\nand not the values themselves. Therefore, the second element of the pair is\nempty (). One by one, we write the label into the first element of each pair.\n<\/p>\n<p>\nAfter the first line is read, we load the values. Here again, we have a\nforeach loop that goes from 0 to the last element of the array. Like the first\nloop, we don&#8217;t need to know how many elements were read, as we let the system\nkeep track of this for us. The second element in each pair of the associative\nlist is loaded with this line:\n<\/p>\n<p>$headers{$headlist[$field]}=@data[$field];<\/p>\n<p>\nLets take a look at this line starting at the left end. From the\narray @data (which is the line we just\nread in), we are accessing the element at the offset that is specified by the\nvariable $field. Because this is just\nthe counter used for our foreach loop,\nwe go through each element of the array data one by one. The value retrieved is\nthen assigned to the left-hand side.\n<\/p>\n<p>\nOn the left, we have an\narray offset being referred to by an array offset. Inside we have\n<\/p>\n<p>$headlist[$field]<\/p>\n<p>\nThe array\nheadlist is what we filled up in the first block. In\nother words, the list of field headings. When we reference the offset with the\n$field <glossary>variable<\/glossary>,\n we get the field\nheading. This will be used as the string for the associative array. The element\nspecified by\n<\/p>\n<p>$headers{$headlist[$field]}<\/p>\n<p>\ncorresponds to  the field value. For example, if the expression\n<\/p>\n<p>$headlist[$field]}<\/p>\n<p>\nevaluated to\ntitle, the second time through the loop, the\nexpression $headers{$headlist[$field}\nwould evaluate to &#8220;2010: Odyssey Two.&#8221;<\/p>\n<p>\nAt this point, we\nare ready to make our next jump. We are going to add the functionality to search\nfor specific values in the data. Lets assume that we know what the fields are\nand wish to search for a particular value. For example, we want all books that\nhave scifi as field char0. Assuming that the script was called book.pl, we would\nspecify the field label and value like this:\n<\/p>\n<p>\nperl book.pl char0=scifi\n<\/p>\n<p>\nOr we could add #!\/usr\/bin\/perl to the top of the\nscript to force the system to use perl as the interpreter. We would run the\nscript like this:\n<\/p>\n<p>\nbook.pl char0=scifi\n<\/p>\n<p>\nThe completed script looks like this:<\/p>\n<p>($searchfield,$searchvalue) =\nsplit(=,$ARGV[0]);<\/p>\n<p>\nopen(INFILE,&#8221;&lt;\nbookdata.txt&#8221;);<\/p>\n<p>$lines=0;<\/p>\n<p>\nwhile\n(&lt;INFILE&gt;)<\/p>\n<p>{<\/p>\n<p>\nchop;<\/p>\n<p>@data = split(&amp;,$_);<\/p>\n<p>\nif (\n$_ eq  &#8221;\n&#8221; )\n<\/p>\n<p>{<\/p>\n<p>\nprint STDERR &#8220;Error:\n&#8220;;<\/p>\n<p>} else {<\/p>\n<p>\nif ( $lines == 0\n)<\/p>\n<p>{<\/p>\n<p>&#9;@headlist=split(&amp;,$_);<\/p>\n<p>&#9;foreach $field\n(0..@headlist-1){<\/p>\n<p>&#9;{3f0b0cf5c640d99e599990c4a720721a04ec3a009b1323dd81fc335ceb655a63}headers = ( $headlist[$field],\n);<\/p>\n<p>}<\/p>\n<p>$lines++;<\/p>\n<p>} else { foreach $field\n(0..@data-1){<\/p>\n<p>&#9;$headers{$headlist[$field]}=@data[$field];<\/p>\n<p>&#9;if\n( ($searchfield eq $headlist[$field] ) &amp;&amp;\n<\/p>\n<p>&#9;&#9;($searchvalue\neq $headers{$headlist[$field]} ))\n{<\/p>\n<p>&#9;$found=1;<\/p>\n<p>&#9;}<\/p>\n<p>&#9;}<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>\nif ( $found\n== 1 )<\/p>\n<p>{<\/p>\n<p>\nforeach $field (0..@data-1){<\/p>\n<p>&#9;print\n$headlist[$field],&#8221;: &#8220;,\n$headers{$headlist[$field]},&#8221;\n&#8220;;<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>$found=0;<\/p><\nP>}<\/p>\n<p>\nWe added a line at the top of the script that splits the\nfirst <glossary>argument<\/glossary>\non\n<\/p>\n<p>\nthe command line:<\/p>\n<p>\n($searchfield,$searchvalue) = split(=,$ARGV[0]);<\/p>\n<p>\nNote that we are\naccessing ARGV[0]. This is not the command being called, as one would expect in\na C or <glossary>shell<\/glossary>\nprogram. Our <glossary>command line<\/glossary>\nhas the string char0=scifi as its\n$ARGV[0]. After the split, we have $searchfield=char0 and $searchvalue=scifi.\n<\/p>\n<p>\nSome other new code looks like this:\n<\/p>\n<p>&#9;if (\n($searchfield eq $headlist[$field] ) &amp;&amp;\n<\/p>\n<p>&#9;&#9;($searchvalue eq $headers{$headlist[$field]} ))\n{<\/p>\n<p>&#9;$found=1;<\/p>\n<p>\nInstead of outputting each line in the\nsecond foreach loop, we are changing it\nso that here we are checking to see if the field we input,\n$searchfield, is the one we just read in\n$headlist[$field] and if the value we are looking\nfor, ($searchvalue), equals the one we\njust read in.\n<\/p>\n<p>\nHere we add another new concept: logical operators. These\nare just like in C, where &amp;&amp; means a logical AND and || is a logical OR.\nIf we want a logical comparison of two variables and each has a specific value,\nwe use the logical AND, like\n<\/p>\n<p>\nif ( $a == 1 &amp;&amp;\n$b = 2)<\/p>\n<p>\nwhich says if\n$a equals 1\nAND $b equals\n2, execute the following block. If we wrote it like\nthis\n<\/p>\n<p>\nif ( $a == 1 || $b = 2)<\/p>\n<p>\nit would\nread as follows: if $a equals 1 OR $b equals 2, execute the block. In our\nexample, we are saying that if the search field ($searchfield) equals the\ncorresponding value in the heading list ($headlist[$field]) AND the search value\nwe input ($searchvalue) equals the value from the file\n($headers{$headlist[$field]}), we then execute the following block. Our block is\nsimply a flag to say we found a match.\n<\/p>\n<p>\nLater, after we read in all the\nvalues for each record, we check the flag. If the flag was set, the foreach loop\nis executed:<\/p>\n<p>\nif ( $found == 1 )<\/p>\n<p>{<\/p>\n<p>\nforeach\n$field (0..@data-1){<\/p>\n<p>&#9;print $headlist[$field],&#8221;: &#8220;,\n$headers{$headlist[$field]},&#8221;\n&#8220;;<\/p>\n<p>}<\/p>\n<p>\nHere we output the\nheadings and then their corresponding values. But what if we aren&#8217;t sure of the\nexact text we are looking for. For example, what if we want all books by the\nauthor Eddings, but do not know that his first name is David? Its now time to\nintroduce the perl function index. As its name implies, it delivers an index.\nThe index it delivers is an offset of one string in another. The syntax\nis\n<\/p>\n<p>\nindex(STRING,SUBSTRING,POSITION)<\/p>\n<p>\nwhere STRING\nis the name of the string that we are looking in, SUBSTRING is the substring\nthat we are looking for, and POSITION is where to start looking. That is, what\nposition to start from. If POSITION is omitted, the function starts at the\nbeginning of STRING. For example\n<\/p>\n<p>\nindex(pie,applepie);<\/p>\n<p>\nwill return 5, as the substring pie\nstarts at position 5 of the string applepie. To take advantage of this, we only\nneed to change one line. We change this\n<\/p>\n<p>\nif ( ($searchfield eq\n$headlist[$field] ) &amp;&amp;\n<\/p>\n<p>&#9;($searchvalue eq\n$headers{$headlist[$field]} )) {<\/p>\n<p>\nto this\n<\/p>\n<p>\nif ( (index($headlist[$field],$searchfield)) != -1 &amp;&amp;\n<\/p>\n<p>&#9;index($headers{$headlist[$field]},$searchvalue) != -1 )\n{<\/p>\n<p>\nHere we are looking for an offset of -1. This indicates the condition\nwhere the substring is <i>not<\/i> within the string. (The offset comes before\nthe start of the string.) So, if we were to run the script like this\n<\/p>\n<p>\nscript.pl author=Eddings\n<\/p>\n<p>\nwe would look through the field\nauthor for any entry containing the string Eddings. Because there are records\nwith an author named Eddings, if we looked for Edding, we would still find it\nbecause Edding is a substring of &#8220;David Eddings.&#8221;\n<\/p>\n<p>\nAs you might\nhave noticed, we have a limitation in this mechanism. We must ensure that we\nspell things with the right case. Because Eddings is uppercase both on the\ncommand line and in the file, there is no problem. Normally names are\ncapitalized, so it would make sense to input them as such. But what about the\ntitle of a book? Often, words like &#8220;the&#8221; and &#8220;and&#8221; are not\ncapitalized. However, what if the person who input the data, input them as\ncapitals? If you looked for them in lowercase, but they were in the file as\nuppercase, you&#8217;d never find them.\n<\/p>\n<p>\nTo consider this possibility, we need to\ncompare both the input and the fields in the file in the same case. We do this\nby using the tr (translate) function. It has the syntax\n<\/p>\n<p>\ntr\/SEARCHLIST\/REPLACEMENTLIST\/[options]<\/p>\n<p>\nwhere SEARCHLIST\nis the list of characters to look for and REPLACEMENTLIST is the characters to\nuse to replace those in SEARCHLIST. To see what options are available, check the\nperl <glossary>man-page<\/glossary>.\n We change part of the script to look like this:\n<\/p>\n<p>\nforeach $field\n(0..@data-1){<\/p>\n<p>&#9;$headers{$headlist[$field]}=@data[$field];<\/p>\n<p>\n($search1 = $searchfield) =~ tr\/A-Z\/a-z\/;<\/p>\n<p>($search2 = $headlist[$field] )\n=~ tr\/A-Z\/a-z\/;\n<\/p>\n<p>($search3 = $searchvalue)=~tr\/A-Z\/a-z\/;<\/p>\n<p>($search4 =\n$headers{$headlist[$field]})=~tr\/A-Z\/a-z\/;<\/p>\n<p>\nif ( (index($search2,$search1)\n!= -1) &amp;&amp; (index($search4,$search3) != -1) )\n{<\/p>\n<p>&#9;$found=1;<\/p>\n<p>&#9;}<\/p>\n<p>}<\/p>\n<p>\nIn the middle of this section\nare four lines where we do the translations. This demonstrates a special aspect\nof the tr function. We can do a translation as we are assigning one <glossary>variable<\/glossary>\nto\nanother. This is useful because the original strings are left unchanged. We must\nchange the statement with the index function and make comparisons to reflect the\nchanges in the variables.\n<\/p>\n<p>\nSo at this point, we have created an interface\nin which we can access a &#8220;database&#8221; and search for specific\nvalues.\n<\/p>\n<p>\nWhen writing conditional statements, you must be sure of the\ncondition you are testing. Truth, like many other things, is in the eye of the\nbeholder. In this case, it is the perl interpreter that is beholding your\nconcept of true. It may not always be what you expect. In general, you can say\nthat a value is true unless it is the null string (), the number zero (0), or\nthe literary string zero (&#8220;0&#8221;).\n<\/p>\n<p>\nOne important feature of perl\nis the comparison operators. Unlike C, there are different operators for numeric\ncomparison and for string comparison. They&#8217;re all easy to remember and you have\ncertainly seen both sets before, but keep in mind that they are different. Table\n0-8 contains a list of the perl comparison operators and Table 0-9 contains a\nlist of perl operations.\n<\/p><b>\n<p>\nTable -8\nperl Comparison\nOperators\n<\/p><\/b>\n<p>\n<center><table BORDER CELLSPACING=1 CELLPADDING=7\nWIDTH=406><tr><td width=\"18{3f0b0cf5c640d99e599990c4a720721a04ec3a009b1323dd81fc335ceb655a63}\" valign=\"TOP\" bgcolor=\"#ffffff\"><b>\n<p>\nNumeric <\/b><\/td><td WIDTH=\"18{3f0b0cf5c640d99e599990c4a720721a04ec3a009b1323dd81fc335ceb655a63}\" VALIGN=\"TOP\"\nBGCOLOR=\"#ffffff\"><b>\n<p>\nString<\/b><\/td><td WIDTH=\"64{3f0b0cf5c640d99e599990c4a720721a04ec3a009b1323dd81fc335ceb655a63}\"\nVALIGN=\"TOP\" BGCOLOR=\"#ffffff\"><b>\n<p>\nComparison<\/b><\/td><\/tr><tr><td WIDTH=\"18{3f0b0cf5c640d99e599990c4a720721a04ec3a009b1323dd81fc335ceb655a63}\" VALIGN=\"TOP\"\nBGCOLOR=\"#ffffff\">\n<p>  ==<\/td><td width=\"18{3f0b0cf5c640d99e599990c4a720721a04ec3a009b1323dd81fc335ceb655a63}\" valign=\"TOP\" bgcolor=\"#ffffff\">\n<p>\neq<\/td><td width=\"64{3f0b0cf5c640d99e599990c4a720721a04ec3a009b1323dd81fc335ceb655a63}\" valign=\"TOP\" bgcolor=\"#ffffff\">\n<p>\nequal\nto<\/td><\/tr><tr><td width=\"18{3f0b0cf5c640d99e599990c4a720721a04ec3a009b1323dd81fc335ceb655a63}\" valign=\"TOP\" bgcolor=\"#ffffff\">\n<p>  !=<\/td><td\nWIDTH=\"18{3f0b0cf5c640d99e599990c4a720721a04ec3a009b1323dd81fc335ceb655a63}\" VALIGN=\"TOP\" BGCOLOR=\"#ffffff\">\n<p>  ne<\/td><td WIDTH=\"64{3f0b0cf5c640d99e599990c4a720721a04ec3a009b1323dd81fc335ceb655a63}\"\nVALIGN=\"TOP\" BGCOLOR=\"#ffffff\">\n<p>\nnot equal to<\/td><\/tr><tr><td WIDTH=\"18{3f0b0cf5c640d99e599990c4a720721a04ec3a009b1323dd81fc335ceb655a63}\"\nVALIGN=\"TOP\" BGCOLOR=\"#ffffff\">\n<p>  &gt;<\/td><td WIDTH=\"18{3f0b0cf5c640d99e599990c4a720721a04ec3a009b1323dd81fc335ceb655a63}\" VALIGN=\"TOP\"\nBGCOLOR=\"#ffffff\">\n<p>  gt<\/td><td WIDTH=\"64{3f0b0cf5c640d99e599990c4a720721a04ec3a009b1323dd81fc335ceb655a63}\" VALIGN=\"TOP\"\nBGCOLOR=\"#ffffff\">\n<p>\ngreater than<\/td><\/tr><tr><td WIDTH=\"18{3f0b0cf5c640d99e599990c4a720721a04ec3a009b1323dd81fc335ceb655a63}\" VALIGN=\"TOP\"\nBGCOLOR=\"#ffffff\">\n<p>  &lt;<\/td><td WIDTH=\"18{3f0b0cf5c640d99e599990c4a720721a04ec3a009b1323dd81fc335ceb655a63}\" VALIGN=\"TOP\"\nBGCOLOR=\"#ffffff\">\n<p>  lt<\/td><td WIDTH=\"64{3f0b0cf5c640d99e599990c4a720721a04ec3a009b1323dd81fc335ceb655a63}\" VALIGN=\"TOP\"\nBGCOLOR=\"#ffffff\">\n<p>\nless than<\/td><\/tr><tr><td WIDTH=\"18{3f0b0cf5c640d99e599990c4a720721a04ec3a009b1323dd81fc335ceb655a63}\" VALIGN=\"TOP\"\nBGCOLOR=\"#ffffff\">\n<p>  &gt;=<\/td><td WIDTH=\"18{3f0b0cf5c640d99e599990c4a720721a04ec3a009b1323dd81fc335ceb655a63}\" VALIGN=\"TOP\"\nBGCOLOR=\"#ffffff\">\n<p>  ge<\/td><td WIDTH=\"64{3f0b0cf5c640d99e599990c4a720721a04ec3a009b1323dd81fc335ceb655a63}\" VALIGN=\"TOP\"\nBGCOLOR=\"#ffffff\">\n<p>\ngreater than or equal to<\/td><\/tr><tr><td WIDTH=\"18{3f0b0cf5c640d99e599990c4a720721a04ec3a009b1323dd81fc335ceb655a63}\"\nVALIGN=\"TOP\" BGCOLOR=\"#ffffff\">\n<p>  &lt;=<\/td><td WIDTH=\"18{3f0b0cf5c640d99e599990c4a720721a04ec3a009b1323dd81fc335ceb655a63}\" VALIGN=\"TOP\"\nBGCOLOR=\"#ffffff\">\n<p>  le<\/td><td WIDTH=\"64{3f0b0cf5c640d99e599990c4a720721a04ec3a009b1323dd81fc335ceb655a63}\" VALIGN=\"TOP\"\nBGCOLOR=\"#ffffff\">\n<p>\nless than or equal to<\/td><\/tr><tr><td WIDTH=\"18{3f0b0cf5c640d99e599990c4a720721a04ec3a009b1323dd81fc335ceb655a63}\"\nVALIGN=\"TOP\" BGCOLOR=\"#ffffff\">\n<p> &lt;=&gt;<\/td><td WIDTH=\"18{3f0b0cf5c640d99e599990c4a720721a04ec3a009b1323dd81fc335ceb655a63}\" VALIGN=\"TOP\"\nBGCOLOR=\"#ffffff\">\n<p>  cmp<\/td><td WIDTH=\"64{3f0b0cf5c640d99e599990c4a720721a04ec3a009b1323dd81fc335ceb655a63}\" VALIGN=\"TOP\"\nBGCOLOR=\"#ffffff\">\n<p>\nnot equal to and sign is returned\n<\/p>\n<p>(0 &#8211; strings equal,\n1 &#8211; first string less, -1 &#8211; first string\ngreater)<\/td><\/tr><\/table><\/center>\n<\/p>\n<p>\nAnother important aspect\nthat you need to keep in mind is that there is really no such thing as a numeric\nvariable. Well, sort of. perl is capable\nof distinguishing between the two without you interfering. If a <glossary>variable<\/glossary>\nis used\nin a context where it can only be a string, then that&#8217;s they way\nperl will interpret it as a string.\n<\/p>\n<p>\nLets take two variables: $a=2 and $b=10. As you might expect, the\nexpression $a &lt; $b evaluates to true because we are using the numeric\ncomparison operator &lt;. However, if the expression were $a lt $b, it would\nevaluate to false. This is because the string &#8220;10&#8221; comes before\n&#8220;2&#8221; lexigraphically (it comes first alphabetically).\n<\/p>\n<p>\nBesides\nsimply translating sets of letters, perl can also do substitution. To show you\nthis, I am going to show you another neat trick of perl. Having been designed as\na text\nand file processing language, it is very common to read in a number of\nlines of data and processing them all in turn. We can tell perl that it should\nassume we want to read in lines although we don&#8217;t explicitly say so. Lets take a\nscript that we call fix.pl. This script looks like this:\n<\/p>\n<p>\ns\/James\/JAMES\/g;<\/p>\n<p>\ns\/Eddings\/EDDINGS\/g;<\/p>\n<p>\nThis syntax is the same as you would find in\nsed; however, perl\n has a much larger set of regular expressions. Trying to run this as a\nscript by itself will generate an error; instead, we run it like this:\n<\/p>\n<p>\nperl -p fix.pl bookdata.pl\n<\/p>\n<p>\nThe -p option tells\nperl to put a wrapper around your\nscript. Therefore, our script would behave as though we had written it like\nthis:<\/p>\n<p>\nwhile (&lt;&gt;)\n{<\/p>\n<p>\ns\/James\/JAMES\/g;<\/p>\n<p>\ns\/Eddings\/EDDINGS\/g;<\/p>\n<p>} continue\n{<\/p>\n<p>&#9;print;<\/p>\n<p>}<\/p>\n<p>\nThis would read each line from a file specified\non the <glossary>command line<\/glossary>,\n carry out the substitution, and then print out each line,\nchanged or not. We could also take advantage of the ability to specify the\ninterpreter with #!. The script would then look like\n<\/p>\n<p>#!\/usr\/bin\/perl\n-p\n<\/p>\n<p>\ns\/James\/JAMES\/g;<\/p>\n<p>\ns\/Eddings\/EDDINGS\/g;<\/p>\n<p>\nAnother\ncommand line option is -i. This stands for &#8220;in-place,&#8221; and with it you\ncan edit files &#8220;in-place.&#8221; In the example above, the changed lines\nwould be output to the screen and we would have to redirect them to a file\nourselves. The -i option takes an <glossary>argument<\/glossary>,\n which indicates the extension you\nwant for the old version of the file. So, to use the option, we would change the\nfirst line, like this:\n<\/p>\n<p>#!\/usr\/bin\/perl\n-pi.old\n<\/p>\n<p>\nWith perl, you can also make your own subroutines. These\nsubroutines can be written to return values, so that you have functions as well.\nSubroutines are first defined with the sub keyword and are called using &amp;.\nFor example:\n<\/p>\n<p>#!\/usr\/bin\/perl\n<\/p>\n<p>\nsub usage\n{<\/p>\n<p>\nprint &#8220;Invalid arguments: @ARGV\n&#8220;;<\/p>\n<p>\nprint &#8220;Usage:\n$0 [-t] filename\n&#8220;;<\/p>\n<p>}<\/p>\n<p>\nif ( @ARGV &lt; 1 || @ARGV &gt; 2 )\n{<\/p>\n<p>&#9;&amp;usage;<\/p>\n<p>}<\/p>\n<p>\nThis says that if the number of arguments\nfrom the <glossary>command line<\/glossary>\n@ARGV is less than 1 or greater than 2, we call the\nsubroutine usage, which prints out a usage message.\n<\/p>\n<p>\nTo create a function,\nwe first create a subroutine. When we call the subroutine, we call it as part of\nan expression. The value returned by the subroutine\/function is the value of the\n<i>last<\/i> expression evaluated.\n<\/p>\n<p>\nLets create a function\nthat prompts you for a yes\/no response:<\/p>\n<p>#!\/usr\/bin\/perl\n<\/p>\n<p>\nif (&amp;getyn(&#8220;Do you *really* want\nto remove all the files in this directory? &#8220;)\n<\/p>\n<p>&#9;eq &#8220;y\n&#8221;\n)<\/p>\n<p>{<\/p>\n<p>&#9;print&#9;&#8221;Don&#8217;t be silly!\n&#8220;<\/p>\n<p>}<\/p>\n<p>\nsub\ngetyn{<\/p>\n<p>\nprint @_;<\/p>\n<p>$response = (&lt;STDIN&gt;);<\/p>\n<p>}<\/p>\n<p>\nThis is a very simple example. In the subroutine\ngetyn, we output everything that is passed to the\nsubroutine. This serves as a prompt. We then assign the line we get from\nstdin to the <glossary>variable<\/glossary>\n$response. Because this is the last expression inside\nthe subroutine to be evaluated, this is the value that is returned to the\ncalling statement.\n<\/p>\n<p>\nIf we enter &#8220;y&#8221; (which would include\nthe new line from the Enter key), the calling if statement passes the actual\nprompt as an <glossary>argument<\/glossary>\nto the subroutine. The getyn subroutine could then be used\nin other circumstances. As mentioned, the value returned includes the new line;\ntherefore, we must check for &#8220;y\n.&#8221;  This is <i>not<\/i> &#8220;y&#8221;\nor &#8220;n,&#8221; but rather &#8220;y#&#8221; followed by a\nnewline.\n<\/p>\n<p>\nAlternatively, we could check the response inside the subroutine.\nIn other words, we could have added the line\n<\/p>\n<p>$response =~\n\/^y\/i;<\/p>\n<p>\nWe addressed the =~ characters earlier in connection with the\ntr function. Here as well, the variable\non the left-hand side is replaced by the &#8220;evaluation&#8221; of the right. In\nthis case, we use a pattern-matching construct:\n\/^y\/i. This has the same behavior as\nsed, where we are looking for a\ny at the beginning of the line. The trailing\ni simply says to ignore the case. If the\nfirst character begins with a y or\nY, the left-hand side (\n$response) is assigned the value 1; if not, it\nbecomes a null string.\n<\/p>\n<p>\nWe now change the calling statement and\nsimply leave off the comparison to &#8220;y\n&#8220;. Because the return value of\nthe subroutine is the value of the last expression evaluated, the value returned\nnow is either &#8220;1&#8221; or &#8220;. Therefore, we don&#8217;t have to do any kind of\ncomparison, as the if statement will react according to the return value.\n<\/p>\n<p>\nI wish I could go on. I haven&#8217;t even hit on a quarter of what\nperl can do. Unfortunately, like the\nsections on sed and\nawk, more details are beyond the scope of this book.\nInstead, I want to refer you to a few other sources. First, there are two books\nfrom O&#8217;Reilly and Associates. The first is <i>Learning\nperl <\/i>by Randal Schwartz. This is a tutorial. The\nother is <i>Programming perl <\/i>by\nLarry Wall and Randal Schwartz. If you are familiar with other <glossary>UNIX<\/glossary>\nscripting\nlanguages, I feel you would be better served by getting the second\nbook.\n<\/p>\n<p>\nThe next suggestion I have is that you get the\nperl <glossary>CD-ROM<\/glossary>\nfrom Walnut Creek CD-ROM\n(<i>www.cdrom.com<\/i>). This is loaded with hundreds of megabytes of\nperl code and the April 1996 version,\nwhich I used, contains the source code for perl\n4 (4.036) and perl5 (5.000m). In\nmany cases, I like this approach better because I can see how to do the things I\nneed to do. Books are useful to get the basics and reminders of syntax, options,\netc. However, seeing someone else&#8217;s code shows me how to do it.\n<\/p>\n<p>\nAnother\ngood <glossary>CD-ROM<\/glossary>\nis the Mother of PERL CD from InfoMagic (<i>www.infomagic.com<\/i>).\nIt, too, is loaded with hundreds of megabytes of\nperl scripts and information.\n<\/p>\n<p>\nThere are a lot\nof places to find sample scripts while you are waiting for the CD to arrive. One\nplace is the Computers and Internet: Programming Languages: Perl hierarchy at\nYahoo. (<i>www.yahoo.com<\/i>). You can use this as a springboard to many sites\nthat not only have information on perl\nbut data on using perl on the Web (e.g.,in <glossary>CGI<\/glossary>\nscripts).\n<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Perl This section is old and incomplete, even as an introduction. Although it covers a number of different aspects of perl, this section really needs to be redone. Any volunteers? If you plan to do anything serious on the Web, &hellip; <a href=\"http:\/\/www.linux-tutorial.info\/?page_id=225\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-225","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"http:\/\/www.linux-tutorial.info\/index.php?rest_route=\/wp\/v2\/pages\/225","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.linux-tutorial.info\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"http:\/\/www.linux-tutorial.info\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"http:\/\/www.linux-tutorial.info\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.linux-tutorial.info\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=225"}],"version-history":[{"count":1,"href":"http:\/\/www.linux-tutorial.info\/index.php?rest_route=\/wp\/v2\/pages\/225\/revisions"}],"predecessor-version":[{"id":655,"href":"http:\/\/www.linux-tutorial.info\/index.php?rest_route=\/wp\/v2\/pages\/225\/revisions\/655"}],"wp:attachment":[{"href":"http:\/\/www.linux-tutorial.info\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=225"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}