1

对于我正在编写的框架,我想测量执行一段(bash)代码需要多少时间,然后以秒为单位打印经过的时间。

为了测量,我执行以下操作:

start=$(date +%s%N)

# do something here

elapsed_time=$(($(date +%s%N) - start))

这给了我经过的秒数和经过的纳秒。如果我现在将其除以 1000000,我将以毫秒为单位获得时间

elapsed_time_in_ms=$(($elapsed time / 1000000))

这一切都很好,似乎可以工作,但真正的问题是我想以这种格式打印它:

12.789s

其中之前.是秒,点之后是 ms 值的最后 3 位。

我将如何实现这样的目标?

编辑

我知道时间可能没有多大用处,但我仍然想实现这一点(即使只是出于美观的原因:-))。

编辑 2

对于任何面临同样问题的人:

最后,我选择使用时间,因为它不需要分叉,而且似乎是最便携的解决方案。

看看这里it的函数和全局total_elapsed_time变量,看看我是如何实现的。

4

4 回答 4

4

您可以使用bc命令:

elapsed_time_in_ms=$(echo "scale=3;$elapsed_time/1000000" | bc)

基本上设置你想要的scale位数.

于 2012-10-10T13:52:45.587 回答
1

这也可以使用 shell 参数扩展或 via 来完成printf。例如,运行以下两个序列,一个接一个地打印出来1349883230.7151349883230.721在一个运行中,1349884003.0251349884003.032另一个运行中。(%N日期格式用前导零填充。)

  s=$(date +%s.%N); s=${s%??????}; echo $s
  t=$(printf "%20.3f" $(date +%s.%N)); echo $t

正如在模式匹配下的 man bash 中提到的,特殊模式字符?匹配任何单个字符。如Parameter Expansion中所述,该表单 ${parameter%word} 删除了匹配的后缀模式:“如果模式匹配尾随部分......扩展是具有最短匹配模式(“%”案例)或最长匹配模式的参数的扩展值(“%%”案例)已删除。”

于 2012-10-10T15:41:29.217 回答
1

只需在前三个纳秒后将数字切掉即可。

printf "%d.%.3ss\n" date +%S date +%N# 顺便说一句,只运行一次 date 可能不是非常不明智的。

-- 打印一个数字后跟一个点,然后将下一个参数视为字符串并仅打印前三个字符。

$ i=0; 而 [ $i -lt 9 ];do i=$((i+1)); 睡眠 0.1;\
       printf "%d.%.3ss\n" `date +%S` `date +%N` ; 完成
33.917 秒
34.025s
34.133s
34.240 秒
34.348s
34.457 秒
34.566s
34.674s
34.784s
于 2012-10-11T05:11:38.177 回答
1

由于使用bc需要时间的隐式分叉,我更喜欢这种纯 bash解决方案:

start=$(date +%s%N);sleep 1.1;elapsed_time=$(($(date +%s%N) - start))
_Z9=000000000
[ ${#elapsed_time} -lt 9 ] && \
    elapsed_time=${_Z9:0:9-${#elapsed_time}}$elapsed_time;
printf "%.3fs\n" ${elapsed_time:0:${#elapsed_time}-9
     }.${elapsed_time:${#elapsed_time}-9}

打印:

1.107s

对于这类事情,我编写了一个小bash 源文件,可以快速完成这项工作。

它在 Linux 上使用/proc/timer_list,或者在 Linux上使用,/proc/uptime或者date +%s%n在其他系统上没有经过很好的测试(欢迎提供反馈;)。

它使用两个计数器(一个用于每次调用,另一个作为整体计数器)并接受一些参数(阅读评论):

. elap.bash
elap -R ; for i in {1..10};do sleep .1; elap Counter $i;done;elap -t total
 0.110488478 Counter 1
 0.111014783 Counter 2
 0.117158015 Counter 3
 0.112897232 Counter 4
 0.111928207 Counter 5
 0.108822248 Counter 6
 0.113464053 Counter 7
 0.117487421 Counter 8
 0.115716626 Counter 9
 0.110493433 Counter 10
 0.008513430      1.137983926 total

而且,bc可能有用:

time echo 'scale=1000;pi=4*a(1);0'|bc -l 
0

real    0m1.590s
user    0m0.768s
sys     0m0.008s

或者

elap -R;elap BC answer is: $(echo 'scale=1000;pi=4*a(1);0'|bc -l )
    1.539957483 BC answer is: 0

使用此脚本/proc/timer_list可以执行以下操作:

elap -R ; for i in {1..10};do elap Counter $i;done;elap -t total
 0.001299574 Counter 1
 0.001574097 Counter 2
 0.005771637 Counter 3
 0.001428803 Counter 4
 0.010423721 Counter 5
 0.004037965 Counter 6
 0.001392464 Counter 7
 0.008092812 Counter 8
 0.001634280 Counter 9
 0.001365652 Counter 10
 0.008201473      0.045222478 total

虽然相同的脚本无法访问 /proc,但使用 forkdate +%s%N给出:

elap -R ; for i in {1..10};do elap Counter $i;done;elap -t total
 0.012148259 Counter 1
 0.013415551 Counter 2
 0.008279329 Counter 3
 0.013700332 Counter 4
 0.012837796 Counter 5
 0.015562929 Counter 6
 0.008062369 Counter 7
 0.016810494 Counter 8
 0.011537439 Counter 9
 0.009731194 Counter 10
 0.012959840      0.135045532 total

我们可以看到分叉有成本(在这种情况下接近 1/100 秒)。

好吧,最后,为了匹配 SO 问题的确切格式,可以修补这个小脚本,以这种方式作为示例:

eval "$(sed -e < elap.bash '
    /6d/{ s/6d.%/10.3f/g;p;N;
        :a;
          s/^.*\n//g;N;s/" \\\n[ \t]*"/./; p;
          s/^.*//g; N;/elaP_elap2/ba; }')"

elap -R ; for i in {1..10};do elap Counter $i;done;elap -t total
     0.001s Counter 1
     0.006s Counter 2
     0.007s Counter 3
     0.004s Counter 4
     0.003s Counter 5
     0.002s Counter 6
     0.001s Counter 7
     0.001s Counter 8
     0.006s Counter 9
     0.002s Counter 10
     0.004s      0.038s total

共 38 秒

于 2013-01-01T13:25:45.067 回答