如何有效地获得脚本的执行时间?


339

我想显示脚本的完成时间。

我目前正在做的是-

#!/bin/bash
date  ## echo the date at start
# the script contents
date  ## echo the date at end

这只是显示脚本开始和结束的时间。是否可以显示细粒度的输出,例如处理器时间/ io时间等?



我认为由于时间上的波动,目前接受的答案还不够。
莱奥波德·赫兹(LéoLéopoldHertz)2016年

1
@CiroSantilli乌坎事件2016六四事件法轮功
莱奥波德·赫兹(LéoLéopoldHertz)2016年


有一个您可以运行的命令,然后它会自动对所有unix命令计时,忘记了如何启用?
powder366

Answers:


448

只需time在调用脚本时使用:

time yourscript.sh

61
这种输出三次realusersys。有关这些含义的信息,请参见此处
加勒特2015年

27
人们可能想知道“真实”-“真实是挂钟时间-从通话开始到结束的时间”
Brad Parks

3
有没有办法将标准输出捕获到文件中?例如,类似time $( ... ) >> out.txt
Jon

1
您也可以在命令行上对命令序列执行此操作,例如:time (command1 && command2)
metar

1
或者他可以在他的剧本,只是做:回声$ SECONDS假设它是bash的....
Crossfit_and_Beer

169

如果time不是一种选择,

start=`date +%s`
stuff
end=`date +%s`

runtime=$((end-start))

30
请注意,这仅在不需要亚秒精度的情况下才有效。对于某些用途可能是可以接受的,对于其他用途则不可以。为了获得更高的精度(date例如,您仍然要调用两次,因此实际上最多只能获得毫秒精度,甚至可能更低),请尝试使用date +%s.%N。(%N自整秒以来为纳秒。)
CVn 2012年

好点子。我刚离开键盘后就想到了,但没有回来。^^还请记住,OP,该“日期”本身将使运行时间增加几毫秒。
Rob Bos

2
@ChrisH哦。很好地指出来;bash算术扩展仅是整数。我看到两个明显的选择;要么在日期格式字符串中舍弃句点(并将结果值视为自大纪元以来的纳秒),请使用date +%s%N,或使用更有能力的东西,bc如jwchew建议的那样根据这两个值来计算实际运行时间。不过,我仍然认为这种方法不是最理想的方法。time由于上述原因,如果有的话,它要好得多。
CVn 2014年

10
只需安装bc然后执行以下操作:runtime=$( echo "$end - $start" | bc -l )
redolent

10
如果您的脚本用了几分钟,请使用:echo "Duration: $((($(date +%s)-$start)/60)) minutes
rubo77 '16

75

times退出脚本时不带参数就调用。

使用kshzsh,也可以使用time。使用zshtime除了用户系统 CPU时间以外,还将为您提供挂钟时间。

要保留脚本的退出状态,可以执行以下操作:

ret=$?; times; exit "$ret"

或者,您也可以在上添加一个陷阱EXIT

trap times EXIT

这样,只要shell退出,时间就会被调用,并且退出状态将被保留。

$ bash -c 'trap times EXIT; : {1..1000000}'
0m0.932s 0m0.028s
0m0.000s 0m0.000s
$ zsh -c 'trap time EXIT; : {1..1000000}'
shell  0.67s user 0.01s system 100% cpu 0.677 total
children  0.00s user 0.00s system 0% cpu 0.677 total

还要注意的是所有的bashkshzsh$SECONDS自动递增得到每秒特殊变量。在zsh和中ksh93,还可以将该变量设置为浮点数(使用typeset -F SECONDS),以提高精度。这只是挂钟时间,不是CPU时间。


12
$ SECONDS变量非常有用,谢谢!
andybuckley 2014年

您的方法是否消除了时间事件的影响?--我认为您的方法time接近前面介绍的方法。我认为timeitMATLAB代码中介绍的方法在这里很有用。
莱奥波德·赫兹(LéoLéopoldHertz),2016年

2
嗨,@StéphaneChazelas。我发现times没有花时间,对吗?例如,bash -c 'trap times EXIT;sleep 2'
user15964


32

我对这个潮流有点迟了,但是想发布我的解决方案(以亚秒为单位的精度),以防其他人偶然通过搜索偶然发现此线程。输出的格式为天,小时,分钟,最后是秒:

res1=$(date +%s.%N)

# do stuff in here

res2=$(date +%s.%N)
dt=$(echo "$res2 - $res1" | bc)
dd=$(echo "$dt/86400" | bc)
dt2=$(echo "$dt-86400*$dd" | bc)
dh=$(echo "$dt2/3600" | bc)
dt3=$(echo "$dt2-3600*$dh" | bc)
dm=$(echo "$dt3/60" | bc)
ds=$(echo "$dt3-60*$dm" | bc)

printf "Total runtime: %d:%02d:%02d:%02.4f\n" $dd $dh $dm $ds

希望那里的人觉得有用!


1
我猜除了使用'bc'进行计算之外,没有其他方法(只有bash可用)。顺便说一句真的很好的剧本;)
tvl 2016年

1
请注意,FreeBSD date不支持亚秒级精度,而只会N在时间戳后附加文字“ ”。
安东·萨姆索诺夫,2016年

1
非常好的脚本,但是我的bash无法处理亚秒级的部分。我还了解到,bc中的/ 1有效地消除了这一点,因此我在$ ds计算中添加了@ / 1 @,它现在显示的内容非常好!
丹尼尔(Daniel)

1
BC支持模:dt2=$(echo "$dt%86400" | bc)。只是说...顺便说一句,我更喜欢这种形式,dt2=$(bc <<< "${dt}%86400")但这完全是个人的。
Dani_l

16

我的方法bash

# Reset BASH time counter
SECONDS=0
    # 
    # do stuff
    # 
ELAPSED="Elapsed: $(($SECONDS / 3600))hrs $((($SECONDS / 60) % 60))min $(($SECONDS % 60))sec"

这确实显示了经过的时间,但没有显示问题中要求的“细粒度输出,例如处理器时间,I / O时间”。
roaima

3
那些寻找所提出问题的答案的人可能会发现此解决方案很有用。您的评论将更好地解决OP的问题。
Mark

5
#!/bin/bash
start=$(date +%s.%N)

# HERE BE CODE

end=$(date +%s.%N)    
runtime=$(python -c "print(${end} - ${start})")

echo "Runtime was $runtime"

是的,这调用了Python,但是如果您可以接受,那么这是一个很好的简洁解决方案。


5
请注意,python在大多数当前系统中,在子外壳中运行该命令并读取其输出将花费数百万个纳秒。跑步也一样date
斯特凡Chazelas

7
“几百万纳秒”是几毫秒。人们对bash脚本的计时通常并不十分担心(除非他们每兆秒运行数十亿个脚本)。
Zilk

2
还要注意,即使计算是在python进程内完成的,这些值是在调用python之前完全收集的。脚本的执行时间将被正确测量,而不会产生“数百万毫微秒”的开销。
维克多·施罗德(VictorSchröder)

5

这个问题已经很老了,但是在尝试找到我最喜欢的方法时,这个线程出现了很多问题……令我惊讶的是,没有人提到它:

perf stat -r 10 -B sleep 1

“ perf”是性能分析工具,包含在内核的“ tools / perf”下,通常可以单独安装(在CentOS中为“ perf”,在Debian / Ubuntu中为“ linux-tools”)。 Linux Kernal perf Wiki拥有有关它的更多信息。

运行“ perf stat”会给出很多细节,包括最后的平均执行时间:

1.002248382 seconds time elapsed                   ( +-  0.01% )

2
什么perf
B层

@B图层-编辑了我的答案,以简要描述'perf'。
Zaahid

1
perf stat现在抱怨“您可能没有收集统计​​信息的权限”。除非您使用来运行一些命令,否则sudo这将在您不完全拥有目标计算机的所有情况下使它无效。
alamar

4

可以在命令之前添加一个小的shell函数以测量其时间:

tm() {
  s=$(date +%s)
  $@
  rc=$?
  echo "took $[$(date +%s)-$s] seconds. return code $rc" >&2
  return $rc
}

然后在脚本或命令行中使用它,如下所示:

tm the_original_command with all its parameters

ilke尝试过增加毫秒数s=$(date +%s000),不确定是否可行。
loretoparisi

3

这是亚历克斯答案的一种变体。我只关心分钟和秒,但是我也希望它采用不同的格式。所以我这样做:

start=$(date +%s)
end=$(date +%s)
runtime=$(python -c "print '%u:%02u' % ((${end} - ${start})/60, (${end} - ${start})%60)")

1
为什么要下票?我有虫子吗?
mpontillo

3
#!/bin/csh
#PBS -q glean
#PBS -l nodes=1:ppn=1
#PBS -l walltime=10:00:00
#PBS -o a.log
#PBS -e a.err
#PBS -V
#PBS -M shihcheng.guo@gmail.com
#PBS -m abe
#PBS -A k4zhang-group
START=$(date +%s)
for i in {1..1000000}
do
echo 1
done
END=$(date +%s)
DIFF=$(echo "$END - $START" | bc)
echo "It takes DIFF=$DIFF seconds to complete this task..."

7
这与已经给出的date在脚本之前和之后使用的其他答案有什么实际区别,并输出它们之间的区别?
埃里克·雷诺夫

2

使用bash,也可以测量和计算一部分Shell脚本的持续时间(或整个脚本的经过时间):

start=$SECONDS

... # do time consuming stuff

end=$SECONDS

您现在可以只打印差异:

echo "duration: $((end-start)) seconds."

如果只需要增加持续时间,请执行以下操作:

echo "duration: $((SECONDS-start)) seconds elapsed.."

您还可以将持续时间存储在变量中:

let diff=end-start

^这是伙计们的答案。或更简单地说:$ SECONDS结尾。这是一个内置的Bash变量。所有其他答案都在做更多的工作来重新发明这个轮子……
Crossfit_and_Beer

2

就个人而言,我喜欢将我的所有脚本代码包装在某个“主要”函数中,如下所示:

main () {
 echo running ...
}

# stuff ...

# calling the function at the very end of the script
time main

请注意time在这种情况下使用该命令是多么容易。显然,您没有测量包括脚本分析时间在内的准确时间,但是我发现它在大多数情况下都足够准确。


1
#!/bin/bash
begin=$(date +"%s")

Script

termin=$(date +"%s")
difftimelps=$(($termin-$begin))
echo "$(($difftimelps / 60)) minutes and $(($difftimelps % 60)) seconds elapsed for Script Execution."

1

基于的计时功能SECONDS仅限于二级粒度,不使用任何外部命令:

time_it() {
  local start=$SECONDS ts ec
  printf -v ts '%(%Y-%m-%d_%H:%M:%S)T' -1
  printf '%s\n' "$ts Starting $*"
  "$@"; ec=$?
  printf -v ts '%(%Y-%m-%d_%H:%M:%S)T' -1
  printf '%s\n' "$ts Finished $*; elapsed = $((SECONDS-start)) seconds"
  # make sure to return the exit code of the command so that the caller can use it
  return "$ec"
}

例如:

time_it sleep 5

2019-03-30_17:24:37 Starting sleep 5 2019-03-30_17:24:42 Finished
sleep 5; elapsed = 5 seconds
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.