在外壳中获取程序执行时间


407

我想在几种不同条件下在linux shell中执行某些操作,并能够输出每次执行的执行时间。

我知道我可以编写一个可以执行此操作的perl或python脚本,但是有没有办法在shell中执行此操作?(碰巧是bash)



是否有可能获得Ticks类似Windows的保护套?
freeforall tousez 2014年

Answers:


534

使用内置time关键字:

$帮助时间

时间:时间[-p]管道
    执行PIPELINE并打印实时,用户CPU时间,
    和终止时执行PIPELINE所花费的系统CPU时间。
    返回状态是PIPELINE的返回状态。-p选项
    以略有不同的格式打印时序摘要。这使用
    TIMEFORMAT变量的值作为输出格式。

例:

$ time sleep 2
真正的0m2.009s
用户0m0.000s
sys 0分0.004秒

1
像这样的命令如何使用time -p i=x; while read line; do x=x; done < /path/to/file.txt?除非我在while循环之前不放任何东西,否则它立即返回0.00。
natli 2012年

这是糟糕的“时间”版本,内置bash。外部“时间”命令在哪里?
Znik

6
@Znik,尝试/ usr / bin / time
Mark Rajcok

10
@natli:虽然time可以按原样定时整个管道(由于是Bash 关键字),但是您需要使用组命令{ ...; ...; })来定时多个命令:time -p { i=x; while read line; do x=x; done < /path/to/file.txt; }
mklement0

2
要查看系统上已安装时间的所有版本,可以使用type -a time
spinup

120

time使用time(1)内置的bash (Robert Gamble提到)相比,您可以获得更多详细的信息。通常是/usr/bin/time

编者注:为确保您调用的是外部实用程序 time而不是shell的time 关键字,请按调用它/usr/bin/time
timePOSIX强制的实用程序,但支持的唯一选项是-p
特定的平台实现特定的非标准扩展:-vGNUtime实用程序一起使用,如下所示(该问题已标记为); BSD / macOS实现用于-l产生类似的输出-请参见man 1 time

详细输出示例:


$ /usr/bin/time -v sleep 1
       Command being timed: "sleep 1"
       User time (seconds): 0.00
       System time (seconds): 0.00
       Percent of CPU this job got: 1%
       Elapsed (wall clock) time (h:mm:ss or m:ss): 0:01.05
       Average shared text size (kbytes): 0
       Average unshared data size (kbytes): 0
       Average stack size (kbytes): 0
       Average total size (kbytes): 0
       Maximum resident set size (kbytes): 0
       Average resident set size (kbytes): 0
       Major (requiring I/O) page faults: 0
       Minor (reclaiming a frame) page faults: 210
       Voluntary context switches: 2
       Involuntary context switches: 1
       Swaps: 0
       File system inputs: 0
       File system outputs: 0
       Socket messages sent: 0
       Socket messages received: 0
       Signals delivered: 0
       Page size (bytes): 4096
       Exit status: 0


2
您不会偶然知道它将来自哪个debian软件包?似乎没有被默认安装
ʞɔıu

1
我是在参考您的帖子Robert。除非您的意思是您建议的命令不是bash内置的?
08年

24
令人惊讶的是,它是从名为“ time”的软件包中安装的。
Paul Tomblin

2
/ usr / bin / time的输出看起来像“ 0.00user 0.00system 0:02.00经过0%CPU(0avgtext + 0avgdata 0maxresident)k 0inputs + 0outputs(0major + 172minor)pagefaults 0swaps”
Paul Tomblin

4
@Nick:“ sudo apt-get安装时间”。
罗伯特·格兰伯

79
#!/bin/bash
START=$(date +%s)
# do something
# start your script work here
ls -R /etc > /tmp/x
rm -f /tmp/x
# your logic ends here
END=$(date +%s)
DIFF=$(( $END - $START ))
echo "It took $DIFF seconds"

14
有更简单的方法。Bash自动计算特殊变量$ SECONDS,然后不需要基于外部日期命令的重新计算。$ SECONDS变量可让bash脚本启动时保持运行秒数。此变量具有一些特殊的属性。参见手册页:D
Znik,

我已经尝试了以上和评论中的方法。在第一个中,我得到一个“非法变量”错误,在第二个中,我得到了“不确定变量”
DrBwts

45

对于逐行增量测量,请尝试gnomon

一个命令行工具,有点像moreutils的ts,用于将时间戳信息放在另一个命令的标准输出之前。对于长时间运行的过程很有用,在该过程中您需要花费很长时间的历史记录。

您还可以使用--high和/或--medium选项指定以秒为单位的长度阈值,超过该阈值,gnomon将以红色或黄色突出显示时间戳。您还可以做其他一些事情。

例


3
一个不错的提示,但要明确一点:这对于逐行计时很有用,但是采用这种细粒度计时的开销会显着增加整体计时。
mklement0

2
太棒了。.感谢您的分享
Kishan B '18

19

如果需要更高的精度,请使用%Nwith date(并bc用于diff,因为它$(())仅处理整数)。

方法如下:

start=$(date +%s.%N)
# do some stuff here
dur=$(echo "$(date +%s.%N) - $start" | bc)

printf "Execution time: %.6f seconds" $dur

例:

start=$(date +%s.%N); \
  sleep 0.1s; \
  dur=$(echo "$(date +%s.%N) - $start" | bc); \
  printf "Execution time: %.6f seconds\n" $dur

结果:

Execution time: 0.104623 seconds

15

如果打算在以后使用时间进行计算,请学习如何使用-f选项/usr/bin/time输出输出节省时间的代码。这是我最近用来获取和分类整个学生程序的执行时间的一些代码:

fmt="run { date = '$(date)', user = '$who', test = '$test', host = '$(hostname)', times = { user = %U, system = %S, elapsed = %e } }"
/usr/bin/time -f "$fmt" -o $timefile command args...

后来我串联了所有$timefile文件,并将输出通过管道传递Lua解释器中。您可以使用Python或bash或您喜欢的语法进行相同的操作。我喜欢这种技术。


注意:完整路径/usr/bin/time是必需的,因为尽管which time会告诉您其他情况,但是如果您仅运行time,它将运行您外壳程序的版本,time该版本不接受任何参数。
Kevin Dice


13

如果只需要秒精度,则可以使用内建$SECONDS变量,该变量计算外壳程序已运行的秒数。

while true; do
    start=$SECONDS
    some_long_running_command
    duration=$(( SECONDS - start ))
    echo "This run took $duration seconds"
    if some_condition; then break; fi
done

10

您可以使用timesubshel​​l ()

time (
  for (( i=1; i<10000; i++ )); do
    echo 1 >/dev/null
  done
)

或在同一shell中{}

time {
  for (( i=1; i<10000; i++ )); do
    echo 1 >/dev/null
  done
}

您发布了两个相同的代码段。您一定要在那里准备一些不同的东西。
stason

3
@StasBekman是不正确的,首先使用()(新上下文,subshel​​l),以及其他使用{}(同一外壳,相同上下文)
Eduardo Cuomo

啊哈!我一直在努力地看待两者,却没有发现区别。感谢您澄清{} vs()。
stason

2

方式是

$ > g++ -lpthread perform.c -o per
$ > time ./per

输出是>>

real    0m0.014s
user    0m0.010s
sys     0m0.002s

无需使用-lphtread-o标签。只需使用time命令,已接受的答案将更好地说明该命令。
丹尼斯

7
这是一个示例。那是我的perform.c具有线程,因此我需要-lpthread,为了简单标识,它是-o per。
Robel Sharma

0

一种可能的简单方法(可能无法满足不同用户的需求)是使用Shell PROMPT。它是一种简单的解决方案,在某些情况下可能会有用。您可以使用bash提示功能,如下例所示:

导出PS1 ='[\ t \ u @ \ h] \ $' 

上面的命令将导致将shell提示符更改为:

[HH:MM:SS用户名@主机名] $ 

每次您运行命令(或按Enter键)返回到shell提示时,该提示都会显示当前时间。

注意:
1)请注意,如果您在键入下一条命令之前等待了一段时间,则需要考虑该时间,即,在shell提示符中显示的时间是显示shell提示符的时间戳,而不是输入命令时的时间戳。一些用户选择按Enter键以获取具有新时间戳记的新提示,然后再准备下一条命令。
2)还有其他可用的选项和修饰符可用于更改bash提示,有关更多详细信息,请参考(man bash)。


不是程序执行的时间,而是程序执行的持续时间。
Geno Chen
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.