Reputation: 193
Below codes is get into a folder($directory)
search for text file and print out the filename and size
. It is working fine if CMD path is c:\modules\STP\New
, it able to read the .txt
files in the specific folder. I guess it is working fine due to it matched the $directory
. Unfortunately, when I run the codes on different path such as c:\modules\STP
, it shows error. The error is Can't call method "size" on a undefined value at line 12
. How can I fix this issue?
my $directory = 'c:\modules\STP\New';
my $file='filename.txt';
my $OUTFILE;
open $OUTFILE, '>>', $file;
my @files = do {
opendir (my $dh, $directory);
grep {/^.*\.txt\z/si} readdir($dh);
};
foreach(@files){
my $filesize = stat($_)->size; #<<<< LINE 12
print { $OUTFILE } "$filesize $_" ,"\n";
}
Expected Result:
I expected the codes can be run in c:\modules\STP
or any other CMD path. I doing this because I wish to reuse the code. Soon the $directory
will not be hardcoded. Any solution or useful resource to share? Thanks!
Upvotes: 1
Views: 2352
Reputation: 593
#!/usr/bin/perl
use strict;
use warnings;
use File::Find;
my @content;
my $basedir = $ARGV[0];
if ( ! $basedir ){ $basedir = '/home/iwts/scripts'; }
find( \&wanted, $basedir );
foreach my $file ( @content ) {
my $cmd = `ls -lh $file | awk '{print \$9 "\t" \$5 }'`;
print $cmd;
}
sub wanted() { if ( $_ =~ m|^.*\.txt| ) { push @content, $File::Find::name; return; } }
Upvotes: 0
Reputation: 35198
You simply need to include full path information when doing a file operation like stat
.
The following is a cleanup of your script:
use strict;
use warnings;
use autodie;
use File::stat;
my $directory = 'c:\modules\STP\New';
my $file = 'filename.txt';
open my $outfh, '>>', $file;
opendir my $dh, "$directory";
while (my $file = readdir $dh) {
next unless $file =~ /\.txt$/i;
my $filesize = stat("$directory\\$file")->size; # Include full path info
print $outfh "$filesize $file\n";
}
To ease the managing of full path and file info, I would recommend using a module like Path::Class
.
The following does the same thing as your script, but ensures you aren't missing path information in your file test:
use strict;
use warnings;
use autodie;
use Path::Class;
my $dir = dir('c:\modules\STP\New');
open my $outfh, '>>', 'filename.txt';
while (my $file = $dir->next) {
next unless $file =~ /\.txt$/i;
printf $outfh "%s %s\n", $file->stat->size, $file->basename;
}
Upvotes: 2
Reputation: 63902
You can also use some CPAN modules, what allows you many additional easying functions, my favorite is Path::Tiny.
From the docs:
This module provide a small, fast utility for working with file paths. It is friendlier to use than File::Spec and provides easy access to functions from several other core file handling modules. It aims to be smaller and faster than many alternatives on CPAN while helping people do many common things in consistent and less error-prone ways.
Your code with Path::Tiny
use 5.010;
use warnings;
use Path::Tiny;
my $directory = $ARGV[0] // "."; #use 1st argument or current dir as default
my $pattern = qr/\.txt$/i; #define your pattern to match
$iter = path($directory)->iterator({ recurse => 0 });
#change to 1, if want recursively search subdirs
while ( $path = $iter->() ) {
next unless $path =~ $pattern;
say "$path: ", $path->stat->size;
}
Upvotes: 0
Reputation: 50637
Use glob()
which already gives full path to files, or add path using map
,
my @files = do {
opendir (my $dh, $directory) or die $!;
map { "$directory/$_" }
grep { /^.*\.txt\z/si }
readdir($dh);
};
Upvotes: 2