Learning Perl, 2nd edition by Randal Schwartz and Tom Christiansen Unconfirmed error reports are from readers. They have not yet been approved or disproved by the author or editor and represent solely the opinion of the reader. This page was updated October 22, 2002. Here's a key to the markup: [page-number]: serious technical mistake {page-number}: minor technical mistake : important language/formatting problem (page-number): language change or minor formatting problem ?page-number?: reader question or request for clarification UNCONFIRMED errors and comments from readers: (15) 6th paragraph (not counting the code fragment): The scalar variable name $someguess has been hyphenated at the end of the line as $some-guess. ?16? This line is confusing: [... insert definition of good_word() here ...] It sounds like it is supposed to go inside of the [ ]. Also, it might be clearer for a beginner to say: [... insert definition of good_word() from previous page here ...] {18} 4th line of code (and several other places in the chapter where this piece of code is repeated): Shouldn't "$words" read "%words"? Compare with line 8 on page 19. {18} 4th paragraph begins: "The while loop reads lines from the wordslist file (via the WORDSLIST file-handle) one line at a time. Each line is stored in the $name variable." THIS IS NOT QUITE RIGHT.... as the storing is alternated first to $name, then $word. See the code above and the explanation after which correctly states the process. So you might say "Each line is stored alternately, first to $name variable via ($name = ), then to $word variable via $word = ;" {18} reads: The while loop reads lines from the wordslist file (via the WORDSLIST file handle) one line at a time. should read: The while statement reads lines from the wordslist file (via the WORDSLIST file handle) a line at a time. Note: The whole loop brings in two lines from the wordslist file, assuming it isn't the end of the file, once in the while statement and another at $word = . {22} We're looping through a set of code to get information from every .secret file in our main directory with this: while ( defined($filename = glob("*.secret")) ) Then in "The Final Programs," this syntax is changed to while ($filename = <<*.secret>) without explanation. From booktech: It is possible to use file name globbing within angle brackets, so while ( defined($filename = glob("*.secret")) ) and while ($filename = <*.secret>) are essentially the same thing. Basically the angle bracket method is older. It won't work with variables. $foo = '*.secret'; @fnames = <$foo>; won't work, but $foo = '*.secret'; @fnames = glob($foo); will work. (22) 4th line from the bottom in the code section: I think it should be: if (-M WORDLIST < 7.0 ) { instead of if (-M WORDLIST >= 7.0 ) { The same mistake happened in page23, 24, 26 in the code section. ?27? first paragraph, *.dir and *.pag: I ended up with a single database file of *.db that the "file" command shows as a Berkely DB hash file. I am using Perl on Redhat Linux, kernel 2.0.? {27} footnote: It says, "The actual permissions of the files will be the logical AND of 0666 and your process's current umask." I suppose that should be ".... _bitwise_ AND of 0666 and _the bitwise NOT of_ your process's current umask." At least, that's how creat(2) does it: (mode & ~umask). {28} "say hello" program, line 6: The truncation and lower-casing of the name should be done here instead of in good_word, so that lastdb won't contain multiple entries for equivalent names. (28) 2nd line in the code of final program: I think it should be: init_words(); instead of: &init_words(); {24} very top: On the very top of page 24 (or on the very bottom of page 23) the line: while ($name = ) { is missing from the source listing. {29} line 26-28 (mid of page, function good_word {} ): The code in these three lines (starting "if ($somename eq "randal")") will never be reached, that has been already excluded in line 6 of this code (starting on page 28: "if ($name =~ /^randal\b/i))." {33} In the 5/99 reprint, changing "double-quoted" back to "single-quoted" doesn't handle 'hello\n' which prints as hello\n not hello In fact, 'hello\\n' results in hello\n, which is exactly the same result. So it is not necessary to "precede the backslash by a backslash" for single-quoted strings. Removing that sentence would help, but also the parenthetical statement on pp 34 top is in question, because, as you can see, preceding a backslash by a backslash within single quotes apparently doesn't have special meaning, despite what even perldata says. [40] 1st paragraph: Shouldnt the -w option of Perl catch the following error: #!/usr/bin/perl -w $result = " 123.45fred" + 10; print "result is $result"; i97-dev(tbryant) # perl sample2.perl result is 133.45i97-dev(tbryant) # (41) paragraph 1, line 1: "operation" should be "operation (aside from dereferencing)". In Perl, dereferencing is implicit, which makes it easy to overlook. (48) Literal Representation: Calling lists containing variables or expressions "literals" is a misnomer. {48} 1st code, line 1: "array" should read "list" (it's not yet an array). {49} 2nd code block, 2nd line: (1.2 .. 5.2) # Same as (1.2, 2.2, 3.2, 4.2, 5.2) It's actually the same as (1, 2, 3, 4, 5). {49} 3rd code example: same error as above. ?49? Confusing: The comment at the end of the line of code says "three element literal array" If it's meaning to refer the reader to the previous code that defines "@a", shouldn't it be *four* element? {49} The third to last line reads: print("The answer is ",$a,"\n); # three element literal array The statement does not compile ("Use of uninitialized value at list line ..."); It should read: print("The answer is ",@a,"\n); # three element literal array {49} ninth line: The use of the list constructor operator is described incorrectly. "This operator creates a list of values starting at the left scaler value up through the right scaler value, incrementing by one each time." Should read "This operator craetes a list of values starting at the integer value of the left scaler value up through the integer value of the right scaler value, incrementing by one each time." The example of (1.2 .. 5.2) #same as (1.2, 2.2, 3.2, 4.2, 5.2) should be (1.2 .. 5.2) #same as (1, 2, 3, 4, 5,) I have tried this on PERL ver 4.018 PL 36 under Slackware ver 2.3 and on PERL ver 5.005.03 on a server at school. ?52? When introducing slices, you might consider throwing in an example where the array subscripts are random, instead of consecutive, ascending values... unless Perl requires consecutive, ascending values (which I kind of doubt). {52} near the bottom of the page: Example says: @fred[1,2] = (9,10); # change the last two values to 9 and 10 The wording "the last two values" only applies for the special case where @fred has only three values. You could instead say, without loss of generality, "change the second and third values to 9 and 10 respectively". {53} examples at top, last line: No slice here. ?53?: From the middle to the bottom, talking about subscripts, you've got conflicting and wrong information. "If you access an array element beyond the ends of the current array (that is, an index of less than zero or greater than the last element's index), the undef value is returned without warning." Not true of negative subscripts, as later "A negative subscript on an array counts back from the end." "Assignment to an array element with a subscript of less than zero is a fatal error.." Not true, it is the same as referencing a negative subscript, it counts from the end. {55} 1st indented example paragraph: Example says: @y = sort(@y); # @y gets 1,16,2,32,4,64,8 This should read: @y = sort(@y); # @y gets (1,16,2,32,4,64,8) Similarly, the line two lines up should read: # @x gets ("large","medium","small") ?67? "Notice once again that accessing an element of a hash requires different punctuation than when you access the entire hash". Make the link back to the arrays section (where @ becoming $ was explained in depth) more clear. {68} Now reads: if (keys(%somehash)){ # if keys() not zero: ...; #array is non empty It is better to write as if (keys(%somehash)){ # if keys() not zero: #array is non empty ...; Since "#array is non empty" is also a part of comment of "if (keys(%somehash))", but not "...". It will be consistent with the style of the book. {70} under Hash Slices: %league{keys %score} = values %score should be @league{keys %score} = values %score (70) Under Topic of "Hash Slices": Two or three more sentences clarifying why the use of @ in print "scores are: @score{@players}\n"; rather than using print "scores are: %score{@players}\n"; The use of @ rather than % when referring to a hash here is worthy of more explanation. Fortunately there is room for it. {78} Line -7 reads: "or put it as the first character within the list". So if we want find a line containing any "]" or an "a", we can use /[]a]/, but it does not work. If we put a backslash, then it is OK. It also works for [. (At first I think [ and ] are treated differently in perl.) {81} Now reads: "In this case , making that match lazy (with a trailing to "?") will actually simplify the work that Perl has to perform, so you may want to consider that". In fact I think ? will do the forward tracking. Therefore $_ = "a xxx ce xxxxci ,,,cd" /a.*?ci.*d/ will also match. It is not true that "the a.*?c now matches the fesest characters between the a and c." The difference between ? and no ? is not only in speed, but some other place as well, see the following example $_= "a xxx c xxxxxxx c xxx d";"; s/c.*d/KK="a xxx c xxxxxxx KK" s/c.*?/KK="a xxx KK" [83] 3rd para. from bottom: This para. states that the caret has special meaning only when "it makes sense to match the beginning of the string." However, Tom Phoenix had this to say: In general, any caret in a regular expression is special and will need to be escaped. To match caret at the beginning of the line, then, /^\^/ will work. {83} \b and \B are different for letters and some symbols, as indicated in the text: /\b\+\b/ matches "x+y" but not "++" or " + ". This is as the same as -,*,/,=,++, Notice that + and * have different meaning if there is no \ before. I guess \ before the symbol changes b to B and vice versa. I suggest to say that "Notice the usage of /,+,*, if we want to search these symbols themselves, we have to put backslash before them, However it will change the meaning of \b and \B." {84} Table 7-2, Sequence and anchoring: Add \b and \B. {84} In the comment of "(a|b)(c|d)", it is better to add "same as [ab][cd]." (85) Now reads: "In this case, yields the next line". It is better to say "the first ". Also it looks bad from a politeness aspect, because we don't care what is the second input and just say "sorry". If so, why should we ask for the second input? (85) first code block, 3rd line: The example goes $a =~ /(.)\l/; # also true .... I would assume that should be the digit "1," not the letter "l"...Same for next line. (88) In line -1: It is better to say "Here the last g makes four matches, every time set a new value for $1, in turns to be "this", "is", "a", and "test"". (Recall "If you want the replacement to operate on all possible matches instead of just the first match".) (90) Middle, "The join function takes a list of values ...": $bigstring = join(@glue, @list); Readers will think the "list" in the first line is just the @list in the second line. Actually in the second line it should be a list of scalar values or arrays, such as $bigstring = join(@glue, $var1,@list1,$var2, ...); And there are two formats, (put "join" in parenthsis or not). {91} Exercise 2.a.: The answer suggested by the authors to this exercise uses the && operator, which is not introduced in the text until p. 106. (94) sub gimme_a_or_b towards the bottom: It says "returns $a" when it should be "return $a." {97} line 18: "@result;" should be "return @result;" {97} In the first paragraph after second code block: The last underscore in "@_[1..$#_]" may be incorrect. {105} line -5: "From." should be "From: ", i.e., that in line -7. (105) Now reads: This set of statements tries all successive values of two small numbers multiplied together until it finds a pair whose product is 63 (7 and 9). Should read: This set of statements tries all successive values of two small numbers multiplied together until it finds a pair whose product is 63 (9 and 7). {113} Table 10-1, -x and -X: should start "File is executable or directory is searchable" (115) line 13: "stat" should use Constant Width font. (125) 2nd section: It says: ... in Chapter 6, Basic I/O, I mentioned that print and print STDOUT were identical, because STDOUT was the default for print .... however, it was in Chapter 10, page 111. {126} Changing the Format Name, line 3: "to" should be "in". [130] bottom while example: On page 86, it shows that you need to put an "m" in front of the new delimiter: m#^/usr/etc# But in the example on page 130: while ( $nextname = ) { $nextname =~ s#.*/##; print "... $nextname\n"; } It took me awhile to figure out why this was working and what did I miss with the syntacts of the # symbol. I didn't read anywhere, even after the example, that this was even using the # as the new delimiter. {133} There's a minor error in the comment in line 3 of the code sample: print "$name\n"; # prints ., .., passwd, group, and so on should read print "$name\n"; # prints ., .., group, passwd, and so on because the list has been sorted. (133) Now reads: On the other hand, it is like the shell's echo*. Should read: On the other hand, it is like the shell's echo *. {137} Creating Hard and Soft Links: paragraph 2, line 1: Swap "to" and "from"; link example, line 2: "fred to bigdumbguy" should be "bigdumbguy to fred"; last paragraph, line 2: swap "to" and "from". {138} symlink example, line 2: "neighbor" should be "barney" ?138? line -1: What does "Fred" mean? should it be "gravelpit"? (138) paragraph 5, line 2: Delete "comparable". {139} Middle: Should "for user" be "for owner"? Also, here the definiton of "owner" and "group" appears (in section Modifying Ownership) after they are used (in section Modifying Permissions), it seems not suitable. {140} second paragraph of "Modifying Timestamps", last sentence: Actually, the time value of UNIX does not overflow in the year 2000, but on Tuesday, January 19, 2038 at 03:14:08 UTC. (Source: David A. Curry: UNIX Systems Programming for SVR 4, O'Reilly & Associates 1996, p. 171.) {143}, I'm pretty sure it should say: system("date >right_now") || die "cannot create right_now"; rather than: system("date >right_now") && die "cannot create right_now"; ^^ {144} line -12: Should "angle brackets" be "single quotes"? ?146? Shouldn't you have something in "Using Processes as Filehandles" about checking the return status of the open(). It is different from the "open() or die" of regular files. {148} para. 2, line 3: "shell" should be "shell command". {150} 4th paragraph: Paragraph 4, sentence 2: "A signal is a one-bit message..." If the signals are numbered with small numbers like 15 or 31, as noted later in the same paragraph, perhaps this should read "A signal is a one-byte message..." Or perhaps I'm being far too literal. {151} last example, line 3: "huge_array" should be "huge_list". {151} Middle, $SIG{'INT'}: In page 68, hash function, usually we use double quotes for keys, here we use single quotes. It is better to say something in page 68, like "we can also use single quotes". {155} 2nd and 3rd paragraphs: The 3rd paragraph states that substr will default the starting position to 0 if the starting position argument is a negative number larger than the length of the string. That's not true; substr behaves as if it created a temporary string and prepended null characters whose number equals the "excess" length. Examples: print(substr("abc",-5,1)."\n"); # prints nothing print(substr("abc",-5,2)."\n"); # prints nothing print(substr("abc",-5,3)."\n"); # prints a The 2nd paragraph makes reference to an "ending position", but there is no ending position in the syntax for substr. ?158? Last paragraph: This paragraph tells us we can sort stringe numerically, and if two strings are numerically equal, sort them by ASCII. That is right from the logic aspect. However if we consider the reality, how could two strings are numerically equal but not the same? {161} line -11: "def became abc and ghi becomes a signle d". It is right. But it will give readers the impression that tr is a command for string replacement (def became abc) and in fact, tr is a command for character replacement. {164} 1/3 down page: "/etc/passwd line split apart" should be "/array/list line split apart" and "an array" should be "a list"> {164} The examples given are: $idnum = getpwuid ("daemon"); $login = getpwnam (25); This should be: $idnum = getpwnam("daemon"); $login = getpwuid(25); Which means the sentence "They each return the thing you've asked them to get" seems incorrect as well. They really return the other thing. Getting the login name returns the ID, getting the ID returns the login name. >From perldoc -f getpwuid: "In scalar context, you get the name, unless the function was a lookup by name, in which case you get the other thing, whatever it is. (If the entry doesn't exist you get the undefined value.) For example: $uid = getpwnam($name); $name = getpwuid($num); " Running the examples seems to bear this out. {166} paragraph 1, line 1: "string value" should be "the string value of their home directory." {167} 1/3 down page: "either ABCD or DCBA, depending on [endian]" I don't have a little-endian to test, but I though it should be "CDAB". {170} paragraph 3, line 3: "array" should be "hash"; paragraph 4, line 2: "array" should be "hash". {171} Opening and Closing DBM Hashes: paragraph 1, line 1: "array" should be "hash"; example 1: ARRAYNAME should be HASHNAME; paragraph 2, line 1: ARRAYNAME should be HASHNAME; example 2, comment: Should be "open mydatabase into %FRED." {171} line -8: "DBM array" should be "DBM hash". ?173? line 12-14: Here >,<,>> are all for read/write, so what is the difference? {175} paragraph 3, line 3: "after" should be "before". ?183? line 8: This URL is corresponding to screen in page 191, so do we need to put one more name=value pair such as "name=someone's name"? ?186? There isn't an index entry for "use" or the qw operator. It needs more explanation other than "we'll employ the qw() notation; this way it will be easier to expand the list later." {186} code example" After END_of_Start, there is a useless my in : my $favorite = param("flavor:); It should read : $favorite = param("flavor"); The added "my" bugs the code. {188} In the HTML code on the form input is given as What's your flavor? The problem is that the CGI script it should talk to (ice_cream, version 2, p. 187) expects input of the form "...?flavor=mint", not "...?favorite=mint". In order for these two to interface properly, the input line in the form should be What's your flavor? ?190? The "use strict" line is never explained except in a brief comment after a pound sign. Anyone who attempts to use it without adding the "my" operator to variables is going to get a rude surprise. It needs a brief but more thorough explanation (and should be in the index) as to why it's being used. (191) Now reads: my $flavor = param("flavor"); my $scoops = param("scoops"); my $taxrate = 1.0743; my $cost = sprintf("%.2f", $taxrate * (1.00 + $scoops * 0.25)); print p("Ok, $who, have $scoops scoops of $flavor for \$$cost."); Should read: my $flavor = param("flavor"); my $scoops = param("scoops"); my $taxrate = 1.0743; my $cost = sprintf("%.2f", $taxrate * (1.00 + $scoops * 0.25)); print p("Ok, $who, have $scoops scoops of $flavor for \$$cost."); {193} line 7, "To add a scrolling list to a form, here's all you need to do": But actually, you are talking about the previous example: Ice Cream Stand. Therefore I suggest to change it to: If instread of popup_menu flavor, we want to use scrolling_list(), we can replace the corresponding line with the following code. print p("What flavor: ", scrolling_list( -NAME => "flavor", -VALUES => [ qw(mint chocolate cherry vanilla peach) ], -LABELS => { mint => "Mighty Mint", chocolate => "cherished chocolate", cherry => "Cheery Cherry", vanilla => "Very Vanila", peach => "Perfectly Peachy", }, -SIZE => 3, -MULTIPLE => 'true', )); And notice that it is better to change "flavors" to "flavor" in the NAME row. ?193-4? The book doesn't have an index entry for the "=>" operator, which is used in the CGI chapter and is never explained (as far as I can tell) in that chapter or the chapter on hashes. {195} 2nd code, third line: You use bail here, but bail isn't mentioned or described so far (it is described much later in the book). (195) I wanted to look at the script example for a guestbook in "Learning Perl, 2nd ed." When I get to the use of the "flock" and "bail" functions on page 195, I think, "I wonder if these were more thoroughly explained earlier in the book..." So I go to the index, but neither function is there. It would seem that if there were any sort of consistent criteria for index keywords, it would be that all functions (that were utilized in the book) would be included. I do get a chuckle out of the "Scooby Doo" joke, but it's not worth the frustration of knowing that I can't rely on the index to get me where I need to go. So I go to the other Perl book on my desk, "Perl in a Nutshell," which does, unlike many of your books, tout itself as "A Desktop Quick Reference." The "flock" function is there, but no "bail." As it stands, I could just copy the script, get a functional guestbook, and not know what the hell any of it meant. That's not what I want, though, and that's not why I buy books from you guys. (198) Now reads: $cur->param("date", scalar localtime); # set to the current time @entries = ($cur); # save message to array Should read: $cur->param("date", scalar localtime); # set to the current time @entries = ($cur); # save message to array {204} bullet 3, line 1: "executable" should be "searchable". {207} Now reads: if ($webdoc->is_success) { # found it print STDOUT "$url: ", $webdoc->title, "\n"; } else { # something went wrong print STDERR "$0: Couldn't fetch $url\n"; Should read: if ($webdoc->is_success) { # found it print STDOUT "$url: ", $webdoc->title, "\n"; } else { # something went wrong print STDERR "$0: Couldn't fetch $url\n"; {213} line 2 of #3: The printed string should end with a newline instead of a blank. {213} answer to number 3: You need to integerize the random number with int(rand(@b)). {216} Program listing and describing text don't suit each other, maybe there is a bit 1st edition and a bit 2nd edition. We think that the end of the first para (after the program listing) and the beginning of 2nd para are not right any longer. [218] Answer 1-e: Answer section says that /(^|\s)(\S+)(\s+\2)+(\s|$)/ will match the same word written two or more times in a row. I have copied my script below; perl -version reports 5.005_03 for sun4-solaris; I'm running Solaris 2.7 on a SparcStation 2. When I run this script and input something like "word\n" then "no match!" is output. If I enter "word word" then "it matches!" is output. However, if I enter something like "word again" then "it matches!" is output which means that the expression is looking for two words, but they do not have to be the same word. I think that the answer given in the back of the book is in error, and if possible I would like to know how to solve this problem correctly. Also, the answer given for exercise 7-1b does not seem to work either, when used in place of the regular expression in the code below... the problem with 7-1b is that the expression matches anything, which is not very instructive. #!/usr/bin/perl -w # # This program will construct a regular expression that matches # the same word written two or more times in a row(with possibly # varying intervening whitespace), where "word" is defined as a # nonempty sequence of nonwhitespace characters. # while(<>) { if(/(^|\s)(\S+)(\s+\2)+(\s|$)/) { print "it matches!\n"; } else { print "no match!\n"; } } {219} Now reads: print if (/^[^aeiou]*a[^eiou]*e[^aiou]*i[^aeou]*o[^aeiu]*u[^aeio]*$ ); Should read: print if (/^[^aeiou]*a[^eiou]*e[^aiou]*i[^aeou]*o[^aeiu]*u[^aeio]*$/i ); {219} The answer for Chapter 7 2c doesn't correctly find words with "aeiou" and in that order. The errata on-line has a correction to permit mixed upper and lower case, but that string is still incorrect. The correct string should read: /^[^aeiou]*a[^aeiou]*e[^aeiou]*i[^aeiou]*o[^aeiou]*u[^aeiou]*$/i {219} Exercise 7.2c: The regular expression string for vowel matching doesn't have a terminating slash /. [221] Code block at top of page: "my($num) = @_; When I typed in the entire example exactly, the return value of the subroutine is always "one". In my own solutionI used: "my($num) = $_[0]; (this works) Is this example incorrect or am I doing something wrong? {221} paragraph 2, line 3: "array element" should be "hash element." [224] code sample for daytime socket client: I cannot get the example to work. (Linux Mandrake 6.0). I tried to work it through as follows: As per perl's suggestion, I typed "h2ph * sys/*" in /usr/include. Then I got an error that stddef.ph could not be found. After finding it I figured out how to add its directory to @INC. Now I am getting error messages that I cannot solve and I am stuck. Here is the output: -------------------------------------------------- Prototype mismatch: sub main::__NFDBITS vs () at (eval 61) line 1. Prototype mismatch: sub main::__FD_SETSIZE vs () at (eval 62) line 1. String found where operator expected at (eval 199) line 1, near "&__const 'struct sockaddr'" (Missing operator before 'struct sockaddr'?) ------------ Here is the code (I commented out a lot to show that the error is early on in the code): -------------------------------------------------- #!/usr/bin/perl BEGIN { $dir ="/usr/lib/perl5/5.00503/i386-linux/linux"; unshift(@INC, $dir) } # why does the following NOT work #use lib $dirl; #print $INC[0], "\n"; #print @INC , "\n"; require 'sys/socket.ph'; $sockaddr = 'S n a4 x8'; chop($hostname = `hostname`); #($name, $aliases, $proto) = getprotobyname('tcp'); #($name, $aliases, $port) = getservbyname('daytime','tcp'); #($name, $aliases, $type, $len, $thisaddress) = gethostbyname($hostname); #$thisport = pack($sockaddr, &AF_INET, 0, $thisaddr); #$thatport = pack($sockaddr, &AF_INET, $port, $thisaddr); # #socket(S, &PF_INET, &SOCK_STREAM, $proto) || # die "cannot create socket\n"; #bind(S, $thisport) || die "cannot bind socket\n"; # optional #connect(S, $thatport) || die "cannot connect socket\n"; #while () { # print; #} #exit 0; (226) #2, paragraph 2, line 1: "prompt" should be "prompt for." {227} #3, last line of program, die message: Swap "new" and "old". {230} #1: The if statement should begin if ($slash == 0) { $head = "/"; $tail = substr($_, 1); } elsif ($slash > 0) { (232) The page ends, Yes, this one needs some explaining. But none appears. Also, there is no answer to question 2. Page(s) seem to be missing. {240} Table B-7 Mathematics: The first item in the module list should be "integer" with a small "i" - currently it's listed as Integer, which doesn't exist. {246} A Simple Client: client code, next to last line: "or" should be ||. {247} Now reads: $remote = IO::Socket::INET->new( Proto => "tcp", PeerAddr => $host, PeerPort => "http(80)", ); Should read: $remote = IO::Socket::INET->new( Proto => "tcp", PeerAddr => $host, PeerPort => "http(80)", ); {249} code, line 11: "or" should be ||. (251) Full Interprocess Communications, paragraph 2: Delete. INDEX: (257) left column: should include $@, page 253 (259) should include bail, 195. (261) should include flock, 112, 195. (264) Should include or, 246, 249. (265) Missing entry in Index for qw() notation. It currently just gives page 186; it should also give page 8. {INDEX} It looks like the chop and chomp functions are indexed together under chop. It would be nice to have a chomp index entry. There are two operators, chomp() and chop(). Unfortunately, the index in Learning Perl doesn't have an entry for chomp() and further combines chomp() references with those of chop(), which is an incorrect assumption. I also noted that the die() operator is listed in the index as having a first reference on page 23, when the actual first reference appears on page 19. It's also curious that the book lists these elements as functions, for example, "die function" whereas the index lists the element as the "die() operator." chop() is supposed to be chomp() [271] Answer to exercise 2, chap 6: Question appears to ask for a program which prints the contents of files upside-down with lines flipped. That is, if two files are being read is being read, and they contain: file #1: whatever whenever file #1: antifignon something file #2: a few more words The output would be: gnihtemos nongifitna revenehw revetahw sdrow erom wef a The answer given in the adendum, however, produces the following output (for the same input) a few more words antifignon something whatever whenever ON-LINE: Near the end of E:\learn\ch05_05.htm, the line %league{keys %score} = values %score; should have a leading "@" instead of "%".