shemyaza has asked for the wisdom of the Perl Monks concerning the following question:

I am trying to put a simple program together to send reminder emails to people at work about one of our QA procedures. I have pieced the following code together from the SAMS book 'Teach Yourself Perl in 24 Hours' but it fails at the print command. Can anyone enlighten me as to why? As far as I can tell I have copied the code from the book exactly.
#!/usr/bin/perl -w use strict; # # Subroutine for reading prev.txt into an array # sub readdata { open (PH, "prev.txt") || die "Cannot open prev.txt: $!"; my(@DATA)=<PH>; chomp @DATA; close (PH); return(@DATA); } # # Test reading of prev.txt by printing the array # print "@DATA"; # # Subroutine for writing array into prev.txt # sub writedata { my(@DATA)=@_; open (PH, ">prev.txt") || die "Cannot open prev.txt: $!"; foreach(@DATA) { print PH "$_\n"; } close (PH); }

Replies are listed 'Best First'.
Re: Printing an array
by Ovid (Cardinal) on Nov 22, 2003 at 20:44 UTC

    It fails at the print command because you have not declared @data (and you haven't called the subroutines, either).

    #!/usr/bin/perl -w use strict; my @data = readdata(); print "@data"; writedata(@data); # # Subroutine for reading prev.txt into an array # sub readdata { open (PH, "prev.txt") || die "Cannot open prev.txt: $!"; my(@DATA)=<PH>; chomp @DATA; close (PH); return(@DATA); } # # Subroutine for writing array into prev.txt # sub writedata { my(@DATA)=@_; open (PH, ">prev.txt") || die "Cannot open prev.txt: $!"; foreach(@DATA) { print PH "$_\n"; } close (PH); }

    Of course, what this does is read the data in, chomp it, and then write it back out with newlines to the same file. Your file will likely remain unchanged. Is that what you wanted? I'm assuming this was simply a test.

    Cheers,
    Ovid

    New address of my CGI Course.

Re: Printing an array
by talexb (Chancellor) on Nov 22, 2003 at 20:44 UTC

    You have defined the subroutine readata, but you haven't called it before your print statement. Hence the array DATA is undefined.

    You probably need to add

    my @DATA = readdata();
    before the print statement.

    --t. alex
    Life is short: get busy!
Re: Printing an array
by duff (Parson) on Nov 22, 2003 at 22:14 UTC

    Looking at the code from a slightly different perspective from the other posters, I'd say that you just need to place the print "@DATA"; line inside of your readdata() routine just before the return @DATA; line.

    But everything the others have said is true too. You haven't called any of these subroutines (at least in the bit of code you showed us) and you haven't declared a variable called @DATA with file scope (you did declare block-scoped variables named @DATA within each of the subroutines but, because they are lexically scoped to the subroutines, they aren't available outside of the subroutines)

      I'd say that you just need to place the print "@DATA"; line inside of your readdata() routine

      The problem with this solution is that we no longer have a "readdata" routine. Instead, we have a routine that should probably be called "read_and_print_data" (or something like that). Subroutines generally should not have side effects like this without good reason. Admittedly, for such a small program it doesn't matter as much, but when the programmer wants to later create a more generalized routine, side effects will cause problems. For example, I almost changed it to this:

      sub read_data { my $file = shift; open FH, '<', $file or die "Cannot open ($file) for reading: $!"; chomp (my @data = <FH>); close FH; return wantarray ? @data : \@data; }

      This routine is a nice little black box that returns an array (or reference) to the lines contained in the file. If you wanted to print out the contents, putting this functionality in the subroutine means that this routine is tough to reuse if you want to just read a file and not print the contents (of course, some might question the use of chomp, given that argument).

      Cheers,
      Ovid

      New address of my CGI Course.

Re: Printing an array
by CountZero (Bishop) on Nov 23, 2003 at 20:10 UTC
    You do understand that the three @DATA arrays are totally different, do you?

    If not, you must check up on the scoping of variables in perl.

    You will have noticed that the readdata-subroutine returns the @DATA array as a flattened list, so you could do a print readdata(); to print the data.

    CountZero

    "If you have four groups working on a compiler, you'll get a 4-pass compiler." - Conway's Law

      Thanks for your help and suggestions. I have read up on subroutines now and come up with the code below. I think this addresses a lot of the points and appears to work quite well but I don't see all of my data file (prev.txt) on screen. Have I still got something wrong? TIA S.
      #!/usr/bin/perl -w use strict; my(@DATAFILE); @DATAFILE=&readdata(); &testcode1(@DATAFILE); &writedata(@DATAFILE); # # Subroutine for reading prev.txt into an array # sub readdata { open (PH, "prev.txt") || die "Cannot open prev.txt: $!"; my(@DATA)=<PH>; chomp @DATA; close (PH); return(@DATA); } # # Subroutine for writing array into prev.txt # sub writedata { my(@DATA)=@_; open (PH, ">prev.txt") || die "Cannot open prev.txt: $!"; foreach(@DATA) { print PH "$_\n"; } close (PH); } # # Subroutines for various tests on the code # sub testcode1 { print "@_"; }
        I tested your code and it runs without a hitch. The testcode-subroutine nicely prints out a textfile I happened to have on the hard-disk.

        Of course it was a smallish file and that may be where your problem lies: perhaps --I'm just guessing here-- your file is so large that when it is printed on the screen, some buffers overrun and not everything is shown or parts get lost.

        CountZero

        "If you have four groups working on a compiler, you'll get a 4-pass compiler." - Conway's Law