Perl不能统计$ _

时间:2018-01-11 18:45:41

标签: perl

我想要目录中每个文件的最后修改时间。为了确保我的循环正常工作,我打印$ _,然后我看到目录的文件名:

{{1}}

我收到此错误

  

在连接(。)或字符串

中使用未初始化的值$ epoch_timestamp

我做错了什么?

4 个答案:

答案 0 :(得分:2)

readdir仅返回文件的名称。如果您当前的工作目录不同,则必须像使用opendir参数一样构建完整路径。最简单的方法是在列表中使用map for循环

我很关心你的陈述

opendir( D, $path . '\/' . $_ ) or die "$!";

\/放在$path$_之间。我认为你只需要/,但插入变量最简单

opendir( D, "$path/$_" ) or die "$!";

$_来自数组@Files。如果这些确实是文件名,则opendir将失败。它们需要是目录名

在我的解决方案中,我将变量$dir构建为

my $dir = "$path/$_"

这样它就可以用于opendir的调用,也可以构建以下for循环中文件的完整路径

请注意,我还使用了词法目录句柄my $dh,它远远优于全局句柄D

for ( @Files ) {

    my $dir = "$path/$_";

    opendir my $dh, $dir or die $!;
    my @textfiles = grep { ! /^\.{1,2}$/ } readdir $dh;

    for ( map { "$dir/$_" } @textfiles ) {

        #    print "$_\n";   <----the file names.
        my $epoch_timestamp = ( stat( $_ ) )[9];

        print "$epoch_timestamp\n";
    }

答案 1 :(得分:1)

或者对于上述完美答案,您可以使用一些模块,让您的生活更轻松。 :)喜欢:Path::Tiny [1]

use 5.014;
use warnings;

use Path::Tiny;

my $path = path('/etc');
my @Files = qw(defaults cups ssl);

for my $dir (@Files) {
    my @textfiles = $path->child($dir)->children;
    for my $file (@textfiles) {
        say "$file: ", $file->stat->mtime;
    }
}

当然,上面的嵌套循环可以写成

for my $dir (@Files) {
    my @textfiles = $path->child($dir)->children;
    say "$_: ", $_->stat->mtime for (@textfiles);
}

并且还不需要将文件列表存储到@textfiles中,因此可以将其缩减为:

for my $dir (@Files) {
    say "$_: ", $_->stat->mtime for ( $path->child($dir)->children );
}
  1. Path :: Tiny在出错时方便地抛出一条干净的异常消息。

答案 2 :(得分:0)

readdir仅返回目录中文件的名称。您需要提供文件的限定路径stat

my $dir_qfn = ...;
opendir(my $dh, $dir_qfn)
    or do {
        warn("Can't read dir \"$dir_qfn\": $!\n");
        next;
    };

while (defined( my $fn = readdir($dh) )) {
   next if $fn =~ /^\.\.?\z/;

   my $qfn = "$dir_qfn/$fn";
   my $mtime = ( stat($qfn) )[9];
   defined($mtime)
       or do {
           warn("Can't stat file \"$file_qfn\": $!\n");
           next;
       };

   ...
}

答案 3 :(得分:0)

使用glob代替

my $dir = ...;

my %ts =
    map { $_ => (stat $_)[9] }
        grep { !m{/\.\.?\z} }    #/
            glob "\Q$dir\E/{*,.*}";

say "ts{$_} => $_" for sort keys %ts;

我使用哈希 name =&gt;时间戳以在数据结构中收集它们。模式$dir/{*,.*}也可以捕获点文件,或者它只是$dir/*

grep过滤掉...个文件名,在m{..}匹配的路径中找到。它的模式需要\Q..\E来防止特定目录名的注入错误。它也会转义空格,因此不需要File::Glob及其:bsd_glob选项。感谢ikegami的评论。

如果您希望一次处理一个文件,请使用glob检索列表,然后迭代它。