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

我当前要做的是-

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


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

评论

stackoverflow.com/questions/385408/…

我认为由于时间波动,目前接受的答案还不够。

@CiroSantilli乌坎事件2016六四事件法轮功我认为您建议的线程仍不足以消除时间事件的影响。

也相关:stackoverflow.com/questions/5152858/…或某种程度上unix.stackexchange.com/questions/334145/…

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

#1 楼

调用脚本时只需使用time

time yourscript.sh


评论


这将输出三次:real,user和sys。有关这些含义,请参见此处。

–加勒特
2015年7月9日在1:56

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

–布拉德公园
16 Mar 29 '16 at 12:19

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

–乔恩
18年4月25日在18:18

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

–会议
18年4月25日在20:30

或者,他也可以按照自己的脚本去做:假设$ bash ...回显$ SECONDS。

–斯科特·普里夫(Scott Prive)
19-2-22在17:10



#2 楼

如果没有time,请

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

runtime=$((end-start))


评论


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

–用户
2012年10月19日19:17



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

–用户
2014年1月23日在13:29



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

–香甜
2015年2月11日在22:01



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

–rubo77
16年7月29日在4:42

除了@ rubo77注释,如果您的脚本需要几个小时,请使用hours = $((runtime / 3600));分钟= $(((运行时%3600)/ 60)); seconds = $(((运行时%3600)%60));回声“运行时:$ hours:$ minutes:$ seconds(hh:mm:ss)”

–汤姆
19年11月13日在15:24



#3 楼

退出脚本后,只需调用不带参数的times即可。

通过kshzsh,您也可以改用time。借助zshtime还将为您提供挂钟时间以及用户和系统CPU时间。

要保留脚本的退出状态,您可以将其设置为:

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


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

trap times EXIT


这样,只要外壳退出,就会调用时间。

$ 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特殊变量,该变量每秒自动递增。在zshksh93中,也可以将该变量设为浮点数(使用typeset -F SECONDS)以提高精度。这只是挂钟时间,不是CPU时间。

评论


$ SECONDS变量非常有用,谢谢!

– andybuckley
14年6月18日在12:00

您的方法是否消除了时间事件的影响? --我认为您的方法是较早提出的近距离方法。我认为MATLAB代码中介绍的timeit方法在这里很有用。

–LéoLéopoldHertz준영
16 Dec 25'9:37

嗨,@StéphaneChazelas。我发现时间不能浪费时间,对吗?例如,bash -c'trap times EXIT; sleep 2'

–user15964
17年6月13日在2:17

@Binarus,是的,该功能来自ksh。与ksh93 / zsh相反,除了不支持浮点的bash之外,它还因为在将SECONDS设置为0之后会在0到1秒后从1更改为1(因为它仅考虑time()的结果)完整的第二粒度)。

–StéphaneChazelas
12月3日9:59

@Binarus,不是介于0和1之间。如果在12:00:00.000将SECONDS设置为0,则它​​将在一秒钟后更改为1。但是,如果将其设置为12:00:00.999,则它将在一毫秒后更改为1。但是,是的,我同意,如果您仍然没有亚秒级的精度,那么在实践中可能并没有多大关系。

–StéphaneChazelas
12月3日,11:18



#4 楼

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

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)

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


希望在那里的人发现这个有用!

评论


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

–tvl
16-4-18在1:19



请注意,FreeBSD的日期不支持亚秒精度,而只会在时间戳后附加文字“ N”。

–安东·萨姆索诺夫(Anton Samsonov)
16年7月12日在9:25

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

–丹尼尔(Daniel)
17年2月1日在6:00

bc支持取模:dt2 = $(回显“ $ dt%86400” | bc)。只是说...顺便说一句,我更喜欢dt2 = $(bc <<<“ $ {dt}%86400”)的形式,但这完全是个人的。

–Dani_l
18 Mar 7 '18 at 16:06

我对bc还是一无所知,但由于以下原因,我被86400除以: leap秒的日子。如果这些天是您要计算的时间跨度的一部分,即介于res1和res2之间(包括这些值),则脚本可能会失败。

– Biinarus
12月3日,11:15

#5 楼

我的bash方法:

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


评论


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

–roaima
17年1月25日在22:10

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

–马克
17年1月26日,0:51



#6 楼

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

main () {
 echo running ...
}

# stuff ...

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


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

评论


很棒的解决方案,不需要额外的工具,并且完全独立。

–卡梅伦·威尔比(Cameron Wilby)
5月3日22:05

#7 楼

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

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% )


评论


什么是性能?

– B层
18年2月20日在14:10

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

–zbateson
18-2-21在15:42

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

– alamar
18-11-22在13:30



太好了,谢谢!比其他人建议的时间更细粒度的解决方案。特别是,时间不适用于测量代码竞争解决方案(因为它不会以毫秒或更短的时间显示时间),而您的解决方案却可以。

– Hi-Angel
3月8日14:25

#8 楼

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

# HERE BE CODE

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

echo "Runtime was $runtime"


是的,它调用Python,但是如果您可以接受,那么这是一个非常不错的简洁解决方案。

评论


请注意,在大多数当前系统上,在子外壳中运行该python命令并读取其输出将花费数百万纳秒。运行日期相同。

–StéphaneChazelas
2014年11月22日10:58

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

–Zilk
16年1月1日在3:34



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

– VictorSchröder
19年2月19日在10:07

上面的时间主要是干净得多...是的,我们可以忍受很多退化,但是如果没有它,它会更好,所以让我们留下来工程师吧!

– Michael Shigorin
7月30日18:11

$(echo $ end-$ start | bc)在没有python的情况下也会做同样的事情

–詹姆斯·麦圭根(James McGuigan)
11月16日的1:09

#9 楼

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

tm() {
  local start=$(date +%s)
  $@
  local exit_code=$?
  echo >&2 "took ~$(($(date +%s)-${start})) seconds. exited with ${exit_code}"
  return $exit_code
}


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

tm the_original_command with all its parameters


评论


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

– loretoparisi
19 Mar 15 '19在22:31

@loretoparisi毫秒,您可以尝试使用date +%s%N。参见serverfault.com/questions/151109/…

– jpbochi
19-10-18在10:29

这很好,除了更安全地使用“ $ @”

– jchook
12月22日20:28

#10 楼

#!/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..."


评论


这与已经给出的使用脚本之前和之后的日期并输出它们之间的差异的其他答案有什么真正的区别?

–埃里克·雷诺夫(Eric Renouf)
16年1月15日在4:11

#11 楼



只需使用time [any command]即可。例如:time sleep 1将在〜1.000到〜1.020秒之间实时睡眠(即,由秒表定时),如下所示:
  $ time sleep 1

 real    0m1.011s
 user    0m0.004s
 sys 0m0.000s
 

多么美丽的东西。您可以在其后放置任何命令,然后以易于理解的形式输出结果。我真的很喜欢将其用于计时构建。例如:
  # time your "make" build
 time make

 # time your "Bazel" build
 time bazel build //path/to/some:target
 

...或者对于可能非常长的git操作,因此我可以建立现实的心理期望:
  # time how long it takes to pull from a massive repo when
 # I'm working from home during COVID-19. NB: `git pull`
 # is sooooo much slower than just pulling the one branch
 # you need with `git pull origin <branch>`, so just fetch
 # or pull what you need!
 time git pull origin master
 



对于更定制的计时需求,您可能需要操纵输出或转换以bash的形式使用内部$SECONDS变量。这是一个演示,包括将这些秒转换为其他单位,例如浮点数分钟:
请注意,在这种情况下,由于我正在使用dt_min函数,因此0.01666666666...0.017(1秒=这么多分钟)四舍五入为printf圆。下面的sleep 1;部分是您调用脚本运行和计时的位置,但是为了演示,我只睡了1秒钟。
命令:
  start=$SECONDS; sleep 1; end=$SECONDS; dt_sec=$(( end - start )); \
 dt_min=$(printf %.3f $(echo "$dt_sec/60" | bc -l)); \
 echo "dt_sec = $dt_sec; dt_min = $dt_min"
 

输出:
  dt_sec = 1; dt_min = 0.017
 



相关:

在我的答案中阅读有关bcprintf的更多信息:https://stackoverflow.com/questions/12722095/how-do-i-use-floating-point-division-in -bash / 58479867#58479867

我不记得我第一次了解time命令的地方了,但这可能来自@Trudbert的回答。


#12 楼

仅使用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变量。所有其他答案都在做额外的工作来重新发明这个轮子。

–斯科特·普里夫(Scott Prive)
19年2月22日在17:08

这只是Marks先前答案unix.stackexchange.com/a/340156/15536​​2的重复。

– Juergen
8月18日1:29

#13 楼

基于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


#14 楼

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

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


评论


为什么要投票?我有虫子吗?

– mpontillo
16 Dec 25 '20:43

对不起,老兄,使用python进行计算对我来说似乎是一个错误。人们为什么不能只打电话给我,这超出了我的范围。

– Michael Shigorin
7月30日18:13

#15 楼

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

Script

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


#16 楼

使用内置的bash时间吗?

time: time [-p] PIPELINE
    Execute PIPELINE and print a summary of the real time, user CPU time,
    and system CPU time spent executing PIPELINE when it terminates.
    The return status is the return status of PIPELINE.  The `-p' option
    prints the timing summary in a slightly different format.  This uses
    the value of the TIMEFORMAT variable as the output format.


示例:

TIMEFORMAT="The command took %Rs"
time {
    sleep 0.1
}


输出:

The command took 0.108s


#17 楼

使用time的公认解决方案写入stderr
使用times的解决方案写入stdout
使用$SECONDS的解决方案缺少亚秒精度。
其他解决方案包括调用诸如dateperf效率不高。
如果您对其中任何一个都满意,请使用它。
但是如果您需要一种有效的解决方案来获得毫秒级精度的时间,并且需要将其转换为变量,以便原始输出仍然不受干扰,您可以将进程替换与time周围的一些重定向结合起来,这比调用外部程序要快得多,并且可以像原始命令/脚本一样围绕时序包装器脚本进行重定向。
解析适合您需要的time输出的变体:
最短的变体,其中将stdout$Cmd写入stderr而不写入stdout
# Preparations:
Cmd=vgs  # example of a program to be timed which is writing to stdout and stderr
Cmd="eval { echo stdout; echo stderr >&2; sleep 0.1; }"  # other example; replace with your own
TIMEFORMAT="%3R %3U %3S"  # make time output easy to parse

长使原始stdoutstderr彼此分离的r变体:
read Elapsed User System < <({ time $Cmd 2>&3; } 3>&2 2>&1 >&3)

最复杂的变体包括关闭额外的文件描述符,以便像在没有此定时包装器的情况下调用$Cmd一样,并且像lvm这样的vgs命令执行不用抱怨文件描述符泄漏:
{ read Elapsed User System < <({ time $Cmd 2>&4; } 4>&2 2>&1 >&3); } 3>&1

您甚至可以伪造bash中的浮点加法而无需调用bc,这会慢得多:
{ read Elapsed User System < <({ time $Cmd 2>&4 4>&-; } 4>&2 2>&1 >&3 3>&-); } 3>&1

两个示例可能的输出慢速CPU上$Cmd的数量:
CPU=`printf %04d $((10#${User/.}+10#${System/.}))`  # replace with your own postprocessing
echo CPU ${CPU::-3}.${CPU: -3} s, Elapsed $Elapsed s >&2  # redirected independent of $Cmd

或:
File descriptor 3 (/dev/pts/1) leaked on vgs invocation. Parent PID 10756: bash
File descriptor 4 (/dev/pts/1) leaked on vgs invocation. Parent PID 10756: bash
  VG   #PV #LV #SN Attr   VSize VFree
  b3     3  24   0 wz--n- 1.31t 1.19t
CPU 0.052 s, Elapsed 0.056 s