[Courses] [Perl] Part 4: Simple File Access

Karine Delvare kproot at nerim.net
Sun Apr 24 21:59:23 EST 2005


On Fri, 22 Apr 2005 14:41:42 +0100
Dan <dan at cellectivity.com> wrote:

> LinuxChix Perl Course Part 4: Simple File Access
>
> 4) Exercises
> 
> a) Write a Perl program that counts the number of lines in a file.
> (Just hard-code the name of the file.)

That one was easily done by removing code from your example :

#!/usr/bin/perl -w
use strict;

# Open file for input (file name preceded by "<").
open MY_INPUT, "< file1.txt" or die "Couldn't open input file: $!";

# Read from input file and count lines.
my $counter = 0;
while ( defined( my $line = <MY_INPUT> ) ) {
  $counter++;
}

# Close the files.
close MY_INPUT;

# Print result
print "The file contains $counter lines.\n";

> b) Write a Perl program that reads a file, strips blank lines and
> outputs the result to another file. To test if a line is (not) blank,
> use:
> 
>   if ( $line ne "\n" ) {
>     # ...
>   }
> 
> Of course, if you chomp() the newline, compare with the empty string
> instead.

I thought the second solution was nicest and I chomped the lines, but of course I forgot to add a newline when writing to the second file... so here is the second version.

#!/usr/bin/perl -w
use strict;

# Open file for input (file name preceded by "<").
open MY_INPUT, "< file1.txt" or die "Couldn't open input file: $!";

# Open file for output (file name preceded by ">").
open MY_OUTPUT, "> file3.txt" or die "Couldn't open output file: $!";

# Read from input file and write to output file.
while ( defined( my $line = <MY_INPUT> ) ) {
  chomp $line;
  if ($line ne "") {
    print MY_OUTPUT "$line\n";
  }
}

# Close the files.
close MY_INPUT;
close MY_OUTPUT;

> c) If you don't specify "<" or ">" in the open statement, the file
> will be opened for reading. Why is it still important to include a
> "<"?

I'd say, for clarity ?

Ok, I tried to go a bit further and called a file "<". But, I don't know how to escape it correctly in the perl script and I couldn't go much further in my test.

> d) Upon reaching the end of a file, the line input operator "<>"
> returns the undefined value, which evaluates to false. So why is it
> necessary to include "defined" in the while loop? Why can't we
> instead it write it like this:
> 
>   while ( my $line = <INPUT> )     # Don't do this! Use "defined"!

Looks like the good ol' error everyone makes in every language. On the last line, <INPUT> will return undefined, so my $line = <INPUT> will succesfully assign the undefined value to $line, and the code in the while loop will be executed one more time, using an undefined value.

> e) Try running the following program:
> 
>   #!/usr/bin/perl -w
>   use strict;
>   
>   open MY_OUTPUT, "| grep 'foo' " or die "Couldn't run grep: $!";
>   
>   print MY_OUTPUT "A line with 'foo' passes.\n";
>   print MY_OUTPUT "A line without it doesn't pass.\n";
>   
>   close MY_OUTPUT;
> 
> What does the vertical bar mean to the "open" statement? What 
> happens if you put the vertical bar after the command rather than 
> before?

I had to run that one to guess what it was doing, and I'm still not sure I fully understand it - I'm not a shell genius. Happily, I use "|grep 'foo' " enough for my own use to know that it will only output the lines that contain 'foo' from what the command before the vertical bar (the pipe if I'm not mistaking) should output.
But here, I have difficulties to find what is the command before.

Running the script, I see that only the first line, with 'foo' in it, is printed, which is not so surprising, but I'm still very confused at the way it is done.

So, MY_OUTPUT is a file handle, but not a file on disk (as I don't see any filename). And, the second argument to open, which should be the name of a file, preceded by "<" or ">" or ">>". That's where I'm lost.

I "intuitively" understand that the two lines written to MY_OUTPUT are immediately processed with "|grep 'foo' ", but I wouldn't be able to explain why.

Reading perldoc -f open doesn't help either as it also states that the second argument gives the filename.

Hmmm... readin further in perldoc, I get :
               If the filename begins with ’⎪’, the filename is interpreted as
               a command to which output is to be piped, and if the filename
               ends with a ’⎪’, the filename is interpreted as a command which
               pipes output to us.

So there it is. I wonder if lack of shell knowledge was the problem, but that one was really not easy.

Even though the second question seems to be answered too, I get errors when I try to put the pipe at the end :
Filehandle MY_OUTPUT opened only for input

> f) Try running the following program:
> 
>   #!/usr/bin/perl -w
>   use strict;
>   
>   open MY_INPUT, "< file1.txt" or die "Couldn't open input file: $!";
>   
>   local $/ = undef;
>   my $content = <MY_INPUT>;
>   print "Content is: [$content]\n";
>   
>   close MY_INPUT;
> 
> What effect does it have to set "$/" to the undefined value?

I did not see any effet, the script outputs my file as is... I was expecting getting the file with no newlines.

Karine


More information about the Courses mailing list