Perl脚本用于打印目录中最后修改的子目录

时间:2014-03-24 02:05:58

标签: perl

我正在编写一个Perl脚本来打印目录中最后修改过的子目录。

例如,目录结构如下

amr/lex/
amr/kik/
amr/rtr/
amr/rtr4/
apr/rtr6tyh/
amr/rtr6yhu/
amr/d5tyh/
amr/d5kuk/
..
..
..

amr中的所有这些目录,例如lexkikrtrrtr4rtr6tyhrtr6yhu,{ {1}}等有子目录

我必须在其中打印最后修改过的子目录

例如

d5yh有2个目录amr/lexs1.0。我必须打印最后修改日期和时间。

到目前为止我有这个

s2.0

我有以下脚本 但它表现不稳定,它打印出最新修改的部分但不适用于其他人

#!/usr/bin/perl -w

use strict;

my $path = '/main/amr';
my $directory;
my @sub_dir;
my $var;


opendir ($directory, $path);

@sub_dir = readdir($directory);

print "@sub_dir";

foreach $var (@sub_dir)
 {
  opendir (my $temp, $var);
  my @arr = readdir ($temp); 
  print "@arr\n";
 }

这里有什么想法错了...... 非常感谢任何帮助

3 个答案:

答案 0 :(得分:1)

这似乎可以使用File::Find

#!/usr/bin/env perl
use strict;
use warnings;
use File::Find;

$ARGV[0] = "." unless scalar @ARGV;
my $new_name = $ARGV[0];
my @info = stat $new_name;
my $new_time = $info[9];

sub wanted
{
    my(@info) = lstat($_);
    my($mod_time) = $info[9];
    if (-d _ && $mod_time > $new_time)
    {
        $new_name = $File::Find::name;
        $new_time = $mod_time;
    }
    return;
}

find(\&wanted, @ARGV);
print "$new_time: $new_name\n";

Perl所以TMTOWTDI - 不止一种方式去做。可能还有一些方法可以优化代码,或使其更简洁。

它给出了合理的答案,例如:

1395633608: .

然后当我在(预先存在的)子目录SHA-256中创建一个文件时,它列出了:

1395633641: ./SHA-256

然后当我使用git签入更改时,它给出了:

1395633722: ./.git

使用Borodin comment中{{3}}建议的问题的不同解释,您可以修改上面的脚本以使用由目录名索引的哈希,其中条目是哈希引用的引用位置hash具有键sub_dir(直接子目录的名称)和mod_time(已识别的子目录的修改时间)。

我在Mac OS X 10.9.2 Mavericks上使用Perl 5.18.2,但除非你的Perl大于5.12,否则你应该没问题。

#!/usr/bin/env perl
use strict;
use warnings;
use File::Find;

$ARGV[0] = "." unless scalar @ARGV;

# dir_mod_times is indexed by directory and contains hash refs
# with keys sub_dir and mod_time.
my %dir_mod_times = ();

sub wanted
{
    my(@info) = lstat($_);
    my($mod_time) = $info[9];
    if (-d _)
    {
        my $ref = { sub_dir => $_, mod_time => $mod_time };
        $dir_mod_times{$File::Find::dir} //= $ref;
        $dir_mod_times{$File::Find::dir}   = $ref
            if ($mod_time > $dir_mod_times{$File::Find::dir}->{mod_time});
    }
    return;
}

find(\&wanted, @ARGV);

foreach my $dir (sort keys %dir_mod_times)
{
    printf "%d: %s/%s\n", $dir_mod_times{$dir}->{mod_time},
           $dir, $dir_mod_times{$dir}->{sub_dir};
}

示例输出:

1395635479: ./.
1395633721: ./.git/objects
1384144591: ./.git/logs/refs
1395598709: ./.git/logs/refs/heads
1395598709: ./.git/logs/refs/heads/so
1395633721: ./.git/objects/02
1395633722: ./.git/refs/heads
1395598709: ./.git/refs/heads/so
1384651972: ./SHA-256/so-20020953-sha256.dSYM
1384651972: ./SHA-256/so-20020953-sha256.dSYM/Contents
1384651972: ./SHA-256/so-20020953-sha256.dSYM/Contents/Resources
1384651972: ./SHA-256/so-20020953-sha256.dSYM/Contents/Resources/DWARF
1395629945: ./time.dSYM/Contents
1395629397: ./time.dSYM/Contents/Resources
1395629945: ./time.dSYM/Contents/Resources/DWARF

然后当我删除SHA-256/junk(空文件)时:

1395635569: ./SHA-256
1395633721: ./.git/objects
1384144591: ./.git/logs/refs
1395598709: ./.git/logs/refs/heads
1395598709: ./.git/logs/refs/heads/so
1395633721: ./.git/objects/02
1395633722: ./.git/refs/heads
1395598709: ./.git/refs/heads/so
1384651972: ./SHA-256/so-20020953-sha256.dSYM
1384651972: ./SHA-256/so-20020953-sha256.dSYM/Contents
1384651972: ./SHA-256/so-20020953-sha256.dSYM/Contents/Resources
1384651972: ./SHA-256/so-20020953-sha256.dSYM/Contents/Resources/DWARF
1395629945: ./time.dSYM/Contents
1395629397: ./time.dSYM/Contents/Resources
1395629945: ./time.dSYM/Contents/Resources/DWARF

答案 1 :(得分:0)

您的程序打开目录/main/amr,然后尝试将该目录中的所有内容打开为另一个目录。

我希望你想要的只是/main/amr中的目录列表,在这种情况下,这个简短的程序会有所帮助。它使用File::Spec::Functions为目录的每个成员构建完整的文件路径,这比使用join

更清晰,更便携
use strict;
use warnings;

use File::Spec::Functions 'catfile';

my $path = '/main/amr';

opendir my ($dh), $path;

while (my $node = readdir $dh) {
  my $fullpath = catfile($path, $node);
  print "$fullpath\n" if -d $fullpath;
}

答案 2 :(得分:0)

这有点棘手,因为它取决于您对目录的修改时间的定义。目录(与所有文件一样)具有与之关联的 mtime 。这是最后一次修改目录。例如,我在目录中添加了一个文件,该目录已被修改。如果我修改目录中的文件,它不会更新目录的修改时间,因为目录本身没有更改。

那么,你是在严格谈论目录的修改时间,还是在谈论那个目录中的任何东西(或者甚至是该目录的子目录)被修改的时间?例如,我修改了该目录中的文件,我是否应该将该文件作为最后一次修改目录,即使该目录未被更改?

简单易行,我们将简单讨论ls -l命令报告的目录修改时间。

首先,在您的脚本中,您需要检查opendir命令的状态以查看是否已成功打开目录,或使用use autodie;自动死亡如果你无法打开目录。我将使用use autodie;,因为它是现在推荐的做事方式。

您还可以使用-M 测试来返回上次修改目录的天数(小数部分)。比使用stat获取mtime要容易得多。

我还建议您在实际需要时使用my声明变量,而不是在程序的最开头声明变量,就好像您使用的是Cobol或Pascal。具有my的变量落入和退出范围,并且可以是变量的有用属性。例如,如果我在循环中定义变量,则一旦离开循环,变量将不再存在。

这就是我的所作所为:

#! /usr/bin/env perl
#
use warnings;
use strict;
use feature qw(say);
use autodie;

my $directory = ".";

opendir ( my $dir_fh, $directory);

my $youngest_date;
my $youngest_subdir;
while ( my $subdir = readdir $dir_fh ) {
    next unless -d $subdir;
    next if $subdir eq "." or $subdir eq "..";

    # If this is the first subdirectory, set it as the youngest and go to the next

    if ( not defined $youngest_subdir ) {
        $youngest_date = -M $subdir;
        $youngest_subdir = $subdir;
        next;
    }

    # See if this subdirectory is younger than the youngest found so far

    if ( $youngest_date > -M $subdir ) {
        $youngest_date = -M $subdir;
        $youngest_subdir = $subdir;
    }
}

if ( $youngest_subdir ) {
    say "Youngest Subdirectory is $youngest_subdir.";
}
else {
    say "No subdirectories found.";

请注意,我在循环外定义$youngest_date$youngest_subdir。这样,它们将存在于循环的每次交互中以及循环结束后。但是,$subdir本身将在循环的每次迭代中不再存在(再次创建它),并且在循环完成后完全消失。

我要做的第一件事是跳过任何不是目录(next unless -d $subdir;)的条目,并跳过...目录。您可能希望跳过任何以句点开头的目录。

一旦我有了一个目录,我就用-M命令查看它的年龄,并将其与$youngest_date进行核对,这是我找到的最年轻的修改日期。另请注意,当我获得第一个目录(if ( not defined $youngest_subdir ) {)时,我必须处理初始条件。

在打印结果之前,我还必须验证是否找到了一个子目录。