Bash 在backticks中使用date命令的perl

Bash 在backticks中使用date命令的perl,bash,perl,Bash,Perl,有很多脚本——实际上,这个商店中所有使用日期的Perl脚本——都使用这种结构。它在backticks中使用date命令。这真的很糟糕吗?它是否打开了一个子shell或其他什么,或者只是不是“perlish”。是否值得我浏览SVN中的所有脚本并将其更改为localtime #!/usr/bin/perl chomp($date=`date '+%Y%m%d'`); if (@ARGV) { $date = $ARGV[0] ; } 为什么不使用perl: $ perl -MPOSIX -e

有很多脚本——实际上,这个商店中所有使用日期的Perl脚本——都使用这种结构。它在backticks中使用date命令。这真的很糟糕吗?它是否打开了一个子shell或其他什么,或者只是不是“perlish”。是否值得我浏览SVN中的所有脚本并将其更改为localtime

#!/usr/bin/perl
chomp($date=`date '+%Y%m%d'`);
if (@ARGV) {
   $date = $ARGV[0] ;
}
为什么不使用perl:

$ perl -MPOSIX -e 'print POSIX::strftime("%Y%m%d", localtime());'
20150106
??您的解决方案几乎完美无缺,需要在较低级别上执行
fork()

这是给出的3个解决方案的基准:代码:

#!/usr/bin/env perl
use strict; use warnings;

use Benchmark qw(:all) ; 
use autodie;

open my $daveNull, ">", "/dev/null";

my $results = timethese(my $count, {
    'POSIX'         => sub {
        use POSIX;
        print $daveNull POSIX::strftime("%Y%m%d", localtime());
    },
    'Time::Piece'   => sub {
        use Time::Piece;
        print $daveNull localtime()->strftime('%Y%m%d');
    },
    'sysdate'       => sub {
        chomp(my $date=`date '+%Y%m%d'`);
        print $daveNull $date;
    },
});
print "-----8<-------------\n";
cmpthese( $results ) ;
#/usr/bin/env perl
严格使用;使用警告;
使用基准qw(:全部);
使用自动模具;
打开我的$daveNull,“>”,“/dev/null”;
my$results=timethis(my$count{
'POSIX'=>sub{
使用POSIX;
打印$daveNull POSIX::strftime(“%Y%m%d”,localtime());
},
'Time::Piece'=>sub{
使用时间::件;
打印$daveNull localtime()->strftime(“%Y%m%d”);
},
“sysdate”=>sub{
chomp(my$date=`date'+%Y%m%d`);
打印$daveNull$日期;
},
});

打印“--8或者您可以只使用Time::Piece,它自5.009005以来一直在核心中

use Time::Piece;
那你就可以

my $t = localtime;
print $t->strftime('%Y%m%d');

这使用strftime格式,但与加载整个POSIX扩展相比,开销要小得多

Plus is有一系列预设格式,其中一种是“ymd”,您可以在其中指定delimter…在本例中,没有

print localtime()->ymd("")

查看更多示例。

至少,只有在需要时才调用shell:

if (@ARGV) {
   $date = $ARGV[0] ;
}
else {
    chomp($date=`date '+%Y%m%d'`);
}
调用shell只是为了扔掉结果,效率要低得多

但是您可以通过多种方式使用纯Perl生成输出。
Time::Piece
模块是一个Perl核心模块,这意味着它总是在那里,或者您可以从提供它的模块之一使用
strftime

$ perl -MTime::Piece -le '$t = new Time::Piece; print $t->ymd("");'
20150106
$ perl -MTime::Piece -le '$t = localtime; print $t->ymd("");'
20150106
$ perl -MTime::Piece -le '$t = localtime; print $t->strftime("%Y%m%d")'
20150106
$ perl -MPOSIX -le 'print strftime("%Y%m%d", localtime(time))'
20150106
$
因此,在上下文中,假设您在文件顶部添加了
use Time::Piece;
,您可以编写:

use Time::Piece;

…

if (@ARGV) {
   $date = $ARGV[0] ;
}
else {
    my $t = localtime;
    $date = $t->ymd("");
}

除非需要,否则不会计算默认日期。

这样调用
date
将打开一个新的shell环境,效率非常低。请使用Benchmark试试,看看它有多糟糕

#!/usr/bin/perl

use strict;
use warnings;
use 5.010;
use Time::Piece;
use POSIX 'strftime';

use Benchmark;

my $fmt = '%Y%m%d';

timethese(100_000, {
  backticks => sub {
    my $date = `date +$fmt`;
  },
  strftime => sub {
    my $date = POSIX::strftime($fmt, localtime);
  },
  timepiece => sub {
    my $date = localtime->strftime($fmt);
  },
});
以下是输出:

Benchmark: timing 100000 iterations of backticks, strftime, timepiece...
 backticks: 108 wallclock secs ( 4.26 usr 25.05 sys +  4.82 cusr 85.59 csys = 119.72 CPU) @ 835.28/s (n=100000)
  strftime:  1 wallclock secs ( 1.03 usr +  0.00 sys =  1.03 CPU) @ 97087.38/s (n=100000)
 timepiece:  1 wallclock secs ( 1.33 usr +  0.00 sys =  1.33 CPU) @ 75187.97/s (n=100000)
backticks解决方案的速度大约是其他两个选项的一百倍


但是,当然,它是有效的。如果您不担心程序的性能,那么就不要费心去更改它。

将bash日期解析为perl会降低perl程序的速度吗?还是会在主机上造成额外的负载?这不是我的解决方案-我问是否应该重写脚本基本基准测试表明使用您的解决方案是快速的r:
real 0m0.003s
用于反刻度,而
real 0m0.018s
用于
strftime()
。等待其他人responses@sputnick这是一个糟糕的基准测试。benchmark.pm说strftime快28倍。我的测试台显示
real 0m0.022s
:比我的解决方案和backtick长。你应该重新检查该基准测试。Perl中的任何解决方案都将比使用backticks的解决方案快得多。不过,不要修复没有损坏的您的示例甚至没有使用它最初设置的
$date
?从SVN切换到git将是对您的时间的更宝贵的利用:)另外两个避免
`date`
的原因到目前为止还没有提到:1)可移植性。您的代码片段将在任何不提供*nix
date
实用程序的机器上失败(例如Windows)。2)错误处理。您的代码不会检查外部命令中的错误,因此如果
date
不在
路径中,例如,
$date
将得到一个伪值,代码将继续运行(希望您在某个点验证日期)。编写额外的代码来处理外部命令中的错误是一件痛苦的事,而且容易出错。使用本机Perl等价物要容易得多。说真的,在这种情况下,“性能”不是问题所在,我不知道为什么答案中会重点放在“性能”上。有更好的理由避免“脱壳”“,如前所述。我认为他这样做的唯一原因是懒散地寻找最好的方法;)
#!/usr/bin/perl

use strict;
use warnings;
use 5.010;
use Time::Piece;
use POSIX 'strftime';

use Benchmark;

my $fmt = '%Y%m%d';

timethese(100_000, {
  backticks => sub {
    my $date = `date +$fmt`;
  },
  strftime => sub {
    my $date = POSIX::strftime($fmt, localtime);
  },
  timepiece => sub {
    my $date = localtime->strftime($fmt);
  },
});
Benchmark: timing 100000 iterations of backticks, strftime, timepiece...
 backticks: 108 wallclock secs ( 4.26 usr 25.05 sys +  4.82 cusr 85.59 csys = 119.72 CPU) @ 835.28/s (n=100000)
  strftime:  1 wallclock secs ( 1.03 usr +  0.00 sys =  1.03 CPU) @ 97087.38/s (n=100000)
 timepiece:  1 wallclock secs ( 1.33 usr +  0.00 sys =  1.33 CPU) @ 75187.97/s (n=100000)