Reputation: 1
My goal: list the *gz files in a directory with name and creation date.
I wrote the following
#!/usr/bin/perl
use strict;
use warnings;
use File::stat;
use Time::localtime;
my $directory = '/home/hans/.config/cqrlog/database';
opendir (DIR, $directory) or die $!;
my @files = (readdir(DIR));
closedir(DIR);
foreach $_ (@files) {
# Use a regular expression to find files ending with .gz
if ($_ =~ m/\.gz$/) {
my $file_name = $_;
my $file_time = (stat($_))[9];
print "$file_time\n";
}
}
But I do keep getting the often seen error "Use of uninitialized value $file_time in concatenation (.) or string at ./perl-matching-files.pl line 18." which is the print line.
I also tried the following:
foreach $_ (@files) {
# Use a regular expression to find files ending with .gz
if ($_ =~ m/\.gz$/) {
my $file_name = $_;
my @file_time_array = (stat($_));
my $file_time = $file_time_array[9];
print $file_name , " - " , $file_time , "\n";
}
}
But again it barfs at the last print line. I also tried a while-loop, but wit the same results. The file names are printed out, though, so I must be doing something right. I feel that when reading through the array the time stamp of the file is not read, but I am not that much of an expert to know what is going wrong. It seems to always come down to the print line. Any insight is appreciated. Cheers.
Upvotes: 0
Views: 348
Reputation: 1
Thank you guys. After two days I got it figured out.
You were both right about the path not being specified enough. Fixed that.
Miller: the glob thing worked after I added use File::stat. I never worked with globs, so thanks for steering me in that direction. Learned a lot from it. Cheers.
In the end I tried the OOP interface for stat after fiddling for an hour with single file examples:
my $file_time = stat("$directory/$file_name")->mtime;
This got me what I wanted, so I tried the same method with the array element number:
my $file_time = (stat("$file_name"))->[9] or die "No $_: $!";
This also worked. So it all came down to adding "->"
This is my final code that works. I know it can be prettier/better/more efficient, but for now it is fine with me, because I wrote it myself. Time to get on with some additions because it is going to be a script only run on my own machine to handle some automation tasks.
#!/usr/bin/perl
use strict;
use warnings;
use File::stat;
use Time::localtime;
my $directory = '/home/hans/.config/cqrlog/database';
opendir (DIR, $directory) or die $!;
my @files = (readdir(DIR));
closedir(DIR);
foreach $_ (@files) {
# Use a regular expression to find files ending with .gz
if ($_ =~ m/\.gz$/) {
# my $file_time = stat("$directory/$_")->mtime;
my $file_time = (stat("$directory/$_"))->[9] or die "No $_: $!";
print "$_\n";
print "$file_time\n";
}
}
Upvotes: 0
Reputation: 35198
stat
returns the empty list if stat fails. Therefore consider test the error code, especially when facing a problem like you were:
my $st = stat($_) or die "No $_: $!";
This would've returned:
No <filename.gz>: No such file or directory at ...
As mpapec already pointed out, this is because you aren't including the path information in the stat
call. There are three possible solutions:
1) chdir
to the directory your iterating over
chdir $directory;
2) Use a glob
instead of readdir
#!/usr/bin/perl
use strict;
use warnings;
my $directory = '/home/hans/.config/cqrlog/database';
for my $file_name (glob("$directory/*.gz")) {
my $st = stat($file_name) or die "No $file_name: $!";
my $file_time = $st->[9];
print "$file_time\n";
}
3) Or manually add the path to the fqfn
my @file_time_array = stat("$directory/$_") or die "No $_: $!";
Upvotes: 0
Reputation: 50647
Instead of
my $file_time = (stat($_))[9];
try
my $file_time = (stat("$directory/$_"))[9];
otherwise you're looking for /home/hans/.config/cqrlog/database
files in the current directory which could work ONLY if you're already in mentioned directory.
Upvotes: 1