我有一个perl脚本,使用system()
调用外部可执行文件。 我想测量这些外部程序占用的CPU秒数。 理想情况下,我想使用shell内置time
命令(这是在Linux系统上)运行它们。 像这样的东西:
system("time /path/to/command")
现在, time
打印输出到stderr,但为了这样做,启动它在一个单独的子shell中给出的命令。 这意味着为了在shell中手动运行时捕获时间输出,需要显式使用子shell并redirect子shell的stderr:
$ time ( command > command.log 2> command.er) 2> time.out
time.out
文件将具有time
命令的输出,而command.er
具有command
的stderr。 不幸的是,括号会破坏Perl的系统调用:
$ time ( ls ) 2> er ## works $ perl -e 'system("time (ls)")' sh: 1: Syntax error: word unexpected (expecting ")")
这意味着我无法捕捉到time
的输出。 为了使事情更好,这似乎是版本相关的:
$ perl --version | head -n2 This is perl 5, version 18, subversion 2 (v5.18.2) built for x86_64-linux-gnu-thread-multi
但是,如果我用一个更新的版本尝试同样的事情:
$ perl --version | head -n2 This is perl 5, version 24, subversion 1 (v5.24.1) built for x86_64-linux-thread-multi $ perl -e 'system("time (ls)")' file1 real 0m0.002s user 0m0.000s sys 0m0.000s
不幸的是,我需要这个在生产机器上运行,所以升级Perl不是一个选项。 那么,如何在Perl 5.18中调用系统调用呢? 我需要user
和sys
值,所以简单地logging开始和结束时间将无济于事。 如果有必要的话,我愿意使用专用模块,尽pipe我更喜欢一个让我使用shell的time
。
更新:事实certificate行为上的差异并不是因为更新的perl版本,而是因为我在Arch系统上testing它的/bin/sh
是bash
而其他命令是在Ubuntu系统上运行的, /bin/sh
是dash
,最小的shell不支持subhells的括号。
您可以使用Capture :: Tiny捕获Perl中几乎任何东西的STDOUT和STDERR。
use Capture::Tiny 'capture'; my ($stdout, $stderr, $exit) = capture { system "time ls" }; print $stderr;
出于某种原因,输出在我的系统上缺少一些空白,但足够清晰,可以解析出你需要的东西。
0.00user 0.00system 0:00.00elapsed 0%CPU (0avgtext+0avgdata 2272maxresident)k 0inputs+8outputs (0major+111minor)pagefaults 0swaps
你用bash
测试过这个命令,但是你把它传给了sh
。
system("time (ls)")
是简短的
system("/bin/sh", "-c", "time (ls)")
但你想要的
system("/bin/bash", "-c", "time (ls)")
$ time ( ls ) 2> er ## works $ perl -e 'system("time (ls)")' sh: 1: Syntax error: word unexpected (expecting ")")
问题是,在第一种情况下,你的shell可能是/bin/bash
而第二种情况是/bin/sh
。 如果你想用另一个shell运行你的命令,你可以使用system LIST
形式:
system("/bin/bash", "-c", "time(ls)")
注1:有PERL5SHELL
环境值,但似乎只在Win32上生效。
注2:如果要测量子进程的CPU时间,可以使用Unix :: Getrusage或BSD :: Resource模块。