我正在编写一个Perl脚本来打印目录中最后修改过的子目录。
例如,目录结构如下
amr/lex/
amr/kik/
amr/rtr/
amr/rtr4/
apr/rtr6tyh/
amr/rtr6yhu/
amr/d5tyh/
amr/d5kuk/
..
..
..
amr
中的所有这些目录,例如lex
,kik
,rtr
,rtr4
,rtr6tyh
,rtr6yhu
,{ {1}}等有子目录
我必须在其中打印最后修改过的子目录
例如
d5yh
有2个目录amr/lex
和s1.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";
}
这里有什么想法错了...... 非常感谢任何帮助
答案 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 ) {
)时,我必须处理初始条件。
在打印结果之前,我还必须验证是否找到了一个子目录。