Reading Learning Perl the Hard Way by Allen B. Downey.
Exercise 1.1 says:
The glob operator takes a pattern as an argument and returns a list of all the files that match the given pattern. A common use of glob is to list the files in a directory.
my @files = glob "$dir/*";
The pattern
$dir/*
means “all the files in the directory whose name is stored in$dir
”. See the documentation of glob for examples of other patterns. Write a subroutine called print dir that takes the name of a directory as a parameter and that prints the file in that directory, one per line.
I did that:
#!/usr/bin/perl
sub print_dir {
my $dir = shift;
my @files = glob "$dir/*";
foreach my $file (@files) {
print "$file\n";
}
}
print_dir @ARGV;
Then Exercise 1.2 says 'Modify the previous subroutine so that instead of printing the name of the file, it prints the contents of the file, using print_file.'
I'm struggling with this one. I have a script that prints the contents of a file:
#!/usr/bin/perl
use strict;
use warnings;
sub print_file {
my $file = shift;
open(my $FILE, $file)
or die $!;
while (my $line = <$FILE>) {
print $line;
}
}
sub cat {
foreach my $file (@_) {
print_file $file;
}
}
cat @ARGV;
And then I have the other script above that prints the names of all files in a directory. So this is what I have so far trying to get all files in a directory and then print the contents of all of those files:
#!/usr/bin/perl
use strict;
use warnings;
sub print_file {
my $file = shift;
open(my $FILE, $file)
or die $!;
while (my $line = <$FILE>) {
print $line;
}
}
sub print_dir {
my $dir = shift;
my @files = glob "$dir/*";
while (my $dir = shift) {
foreach my $file (@files) {
print_file "$file";
}
}
}
print_dir @ARGV;
And obviously it's not working and there is no error message either.
CodePudding user response:
You add a line feed to the file name for no reason.
print_file "$file\n";
should be
print_file $file;
By the way, it's a bad practice to use global vars (like FILE
) for nothing. And it's a good idea to check open
for errors as it's quite prone to them.
open my $FILE, $file
or die "Can't open \"$file\": $!\n";
while (my $line = <$FILE>) {
...
}
With your bug, this would have output something like
Can't open "./some_file
": No such file or directory
CodePudding user response:
Following code snippets demonstrate two possible solutions to your exercises.
Perl code can be very concise in expression of desired algorithm (principle of: brevity is the soul of wit).
Note 1: code verifies that passed argument is a directory
Note 2: code skips the output of content of directory as it is not a file
use strict;
use warnings;
use feature 'say';
print_dir($_) for @ARGV;
sub print_dir {
my $dir = shift;
die "$dir isn't a directory" unless -d $dir;
say for glob("$dir/*");
}
Modified code to print content of the files
use strict;
use warnings;
use feature 'say';
print_dir($_) for @ARGV;
sub print_dir {
my $dir = shift;
die "$dir isn't a directory" unless -d $dir;
for my $fname ( glob("$dir/*") ) {
next if -d $fname; # skip directories
say "\n" . '-' x 25
. "\n" . $fname
. "\n" . '-' x 25;
open my $fh, '<', $fname
or die "Couldn't open $fname";
print while <$fh>;
close $fh;
}
}
Reference:
- -X file test
- glob
- open
- die
- say
- perlvar
- Tutorial: Perl file test operators
- Tutorial: Perl special variables
Recomendation: