关于Linux:在shell中获取程序执行时间

Get program execution time in the shell

我想在Linux shell中在几个不同的条件下执行一些东西,并且能够输出每次执行的执行时间。

我知道我可以编写一个Perl或python脚本来完成这个任务,但是有没有一种方法可以在shell中完成呢?(恰巧是巴什)


使用内置的time关键字:

1
2
3
4
5
6
7
8
$ help time

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.

例子:

1
$ time sleep 2
1
2
3
real    0m2.009s
user    0m0.000s
sys     0m0.004s


您可以得到比bash内置的time更详细的信息(robert gamble提到)使用时间(1)。通常这是/usr/bin/time

编者按:为了确保调用外部实用程序time,而不是shell的time关键字,请将其作为/usr/bin/time调用。time是一个POSIX授权的实用程序,但它需要支持的唯一选项是-p。特定平台实现特定的、非标准的扩展:-v与GNU的time实用程序一起工作,如下所示(问题被标记为Linux);bsd/macos实现使用-l生成类似的输出-请参阅man 1 time

详细输出示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<wyn>
$ /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
</wyn>


1
2
3
4
5
6
7
8
9
10
#!/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"


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

A command line utility, a bit like moreutils's ts, to prepend timestamp information to the standard output of another command. Useful for long-running processes where you'd like a historical record of what's taking so long.

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

example


如果您希望更精确,请使用%Ndate进行比较(并使用bc进行比较,因为$(())只处理整数)。

方法如下:

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

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

例子:

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

结果:

1
Execution time: 0.104623 seconds

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

1
2
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或您最喜欢的任何语法执行相同的操作。我喜欢这种技巧。


如果只需要精确到第二个,可以使用内置的$SECONDS变量,该变量计算shell运行的秒数。

1
2
3
4
5
6
7
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

您可以使用time和subshell ()

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

或在同一壳体中,{}

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


方式是

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

输出>

1
2
3
real    0m0.014s
user    0m0.010s
sys     0m0.002s


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

1
export PS1='[\t \u@\h]\$'

上述命令将导致将shell提示更改为:

1
[HH:MM:SS username@hostname]$

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

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