如何以 diff 命令返回的格式获取 perl 中文件的最后修改时间?

How to get last modified time of a file in perl in the format returned from diff command?

我想以与 linux diff 命令相同的格式显示时间。

D:\>diff -dub old.cfg new.cfg
--- old.cfg       2019-05-15 15:03:14.289950700 +0530
+++ new.cfg       2019-05-14 16:07:21.119695300 +0530

我想将文件的最后修改时间显示为 2019-05-15 15:03:14.289950700 +0530
我使用了 stat 但我没有得到那个纳秒部分。 Alo,需要给定格式的时区。我也试了Time::HiRes,但没成功。

my $dt = strftime("%Y-%m-%d %H:%M:%S", localtime((stat($old_file))[9]));

它returns:2019-05-15 15:03:14。你能帮我附加其他信息吗?

我必须首先声明,这并不准确。即使您的硬件在返回到软件时可能支持纳秒级分辨率,它也有数百倍的差距。 (对于文件的时间戳,大概仅用作相对于其他文件的时间戳,可能不太重要。)

话虽如此,我发现要求纳秒的唯一方法是使用系统的工具,所以 stat

my ($ts) = grep { /^\s*Access: [0-9]{4}/ } qx(stat $file);
$ts =~ s/^\s*Access:\s+//;

或者,使用 map 也作为过滤器

my ($ts) = map { /^\s*Access:\s+([0-9]{4}.*)/ ?  : () } qx(stat $file);

当然,这里的一个问题是我们必须解析输出;所以请查看您的手册页并测试您的 stat,并且不要希望有太大的可移植性。注意系统变化,因为程序的输出格式可能会改变。但是我没有在 Perl 中找到纳秒声明。

供参考,在我的 CentOS 7 上(在 bashtcsh 下)

perl -we'$f=shift; print grep { /^\s*Access: [0-9]{4}/ } qx(stat $f)' file

打印,随机文件

Access: 2019-05-15 13:21:57.723987422 -0700

再次强调,"nano"秒根本不准确。


另一种选择,可能更可靠的输出解析,是使用 ls 及其 --full-time

my $ts = join ' ', (split ' ', qx(ls --full-time $file))[5..7];

一如既往,当 运行 外部命令小心构建变量并适当引用和转义时。一个好的工具是String::ShellQuote。或者,除非特别需要,否则最好完全避免使用 shell。最好使用 运行 外部工具的模块。

这是一个 multi-part 挑战。第一个挑战是在文件时间上获得 sub-second 分辨率,即 OS 和 filesystem-dependent。第二部分是获取本地时区偏移量。然而,所有这些在现代系统上都是可行的。 Time::HiRes 你走在正确的轨道上,但 strftime() 只会让你分道扬镳。这是一个示例程序,它将文件作为参数并根据您的要求打印 hi-res mtime。

#!/usr/bin/perl

use strict;
use warnings;

use Time::HiRes qw(stat);
use Time::Piece;
use Time::Seconds;

sub timestr {
    my $t = localtime($_[0]);
    my $tstr = $t->strftime('%Y-%m-%d %H:%M:%S');
    if ($_[0] =~ /(\.\d+$)/) { $tstr .=  }
    my $off = $t->tzoffset;
    return sprintf('%s %+02d%02d', $tstr, int($off->hours), $off->minutes % 60);
}

for (@ARGV) {
    my @stat = stat($_);
    print "$_\n  ".($! ? "Error: $!" : timestr($stat[9]))."\n";
}
exit(0);

示例输出:

$ ./stat.pl stat.pl
stat.pl
  2019-05-16 20:02:38.76708 +1000

许多繁重的工作由 Time::Piece 完成,但有一些 hackery 继续提取时间的小数部分,并将时区转换为所需的格式(和我还没有广泛测试它)。您可能希望对原始传入值使用 sprintf() 来强制保留特定数量的小数位。我的代码只是诚实地再现了原始的小数部分。

请记住,并非所有时间戳都有小数部分,即使在支持 sub-second 分辨率的文件系统上也是如此。例如,该文件可能是从没有 sub-second 分辨率的来源复制的。