【发布时间】:2017-10-10 11:31:35
【问题描述】:
我有一个使用system() 调用外部可执行文件的perl 脚本。我想测量这些外部程序占用的 CPU 秒数。理想情况下,我想使用 shell 内置 time 命令运行它们(这是在 Linux 系统上)。像这样的:
system("time /path/to/command")
现在,time 将其输出打印到 stderr,但为了这样做,请启动在单独的子 shell 中给出的命令。这意味着,为了在 shell 中手动运行时捕获时间的输出,您需要显式使用子 shell 并重定向子 shell 的 stderr:
$ time ( command > command.log 2> command.er) 2> time.out
文件time.out 将具有time 命令的输出,而command.er 具有command 的标准错误。不幸的是,括号破坏了 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 值,所以简单地记录开始和结束时间是没有帮助的。如果有必要,我愿意使用专用模块,尽管我更喜欢让我使用 shell 的time 的技巧。
更新:事实证明,行为上的差异不是因为更新的 perl 版本,而是因为我在 Arch 系统上测试了它,其 /bin/sh 是 bash,而其他命令正在运行/bin/sh 为 dash 的 Ubuntu 系统,这是一个不支持子 shell 括号的最小 shell。
【问题讨论】:
-
您可以使用metacpan.org/pod/Capture::Tiny 直接捕获STDERR。
-
sh: 1: Syntax error表示错误来自/bin/sh,而不是来自perl。 -
@el.pescado 是的,我知道,但这是因为 perl 调用命令的方式。请注意,当直接在 shell 中运行时,同样的事情可以正常工作,更重要的是,当使用更新版本的 Perl 运行时,它也可以正常工作。
-
@simbabque 谢谢,我会试试的。但是,我担心它只会捕获命令运行的标准错误,而不是
time。两者是分开的。 -
值得记住的是,您的交互式 shell 可能与
system调用使用的 shell 不同。通常bin/sh是/bin/bash的符号链接,但AFAIR Ubuntu 使用/bin/bash作为交互式shell,/bin/dash用于执行脚本(包括system)。
标签: linux perl time system-calls