如何测量程序执行时间并将其存储在变量中

如何测量程序执行时间并将其存储在变量中

为了找出 Bash (v4+) 脚本中的某些操作需要多长时间,我想time“单独”解析命令的输出并(最终)在 Bash 变量 ( let VARNAME=...) 中捕获它。

现在,我正在使用time -f '%e' ...(或者更确切地说command time -f '%e' ...是因为内置的 Bash),但由于我已经重定向了执行命令的输出,所以我真的不知道如何捕获命令的输出time。基本上这里的问题是分离输出来自time执行命令的输出。

我想要的是功能性计算启动命令和完成之间的时间量(以秒为单位)。它不一定是time命令或相应的内置命令。


编辑:鉴于下面两个有用的答案,我想添加两个说明。

  1. 我不想丢弃执行命令的输出,但它最终出现在 stdout 还是 stderr 上并不重要。
  2. 我更喜欢直接方法而不是间接方法(即直接捕获输出而不是将其存储在中间文件中)。

到目前为止使用的解决方案date接近我想要的。

答案1

要将 的输出time放入 var 中,请使用以下命令:

usr@srv $ mytime="$(time ( ls ) 2>&1 1>/dev/null )"
usr@srv $ echo "$mytime"

real    0m0.006s
user    0m0.001s
sys     0m0.005s

您也可以只请求单一时间类型,例如 utime:

usr@srv $ utime="$( TIMEFORMAT='%lU';time ( ls ) 2>&1 1>/dev/null )"
usr@srv $ echo "$utime"
0m0.000s

要获取时间,您还可以使用date +%s.%N,因此在执行之前和之后获取时间并计算差异:

START=$(date +%s.%N)
command
END=$(date +%s.%N)
DIFF=$(echo "$END - $START" | bc)
# echo $DIFF

答案2

如果您处于bash(而不是sh)并且不需要亚秒级精度,则可以date完全跳过调用并执行此操作,而无需生成任何额外的进程,无需分离组合输出,也无需捕获和解析输出从任何命令:

# SECONDS is a bash special variable that returns the seconds since set.
SECONDS=0
mycmd <infile >outfile 2>errfile
DURATION_IN_SECONDS=$SECONDS
# Now `$DURATION_IN_SECONDS` is the number of seconds.

答案3

在 bash 中,构造的输出time将转到其标准错误,并且您可以重定向其影响的管道的标准错误。因此,让我们从写入其输出和错误流的命令开始sh -c 'echo out; echo 1>&2 err':为了不将命令的错误流与 的输出混淆time,我们可以暂时将命令的错误流转移到不同的文件描述符:

{ time -p sh -c 'echo out; echo 1>&2 err' 2>&3; }

这将写入outfd 1、errfd 3,并将时间写入 fd 2:

{ time -p sh -c 'echo out; echo 1>&2 err' 2>&3; } \
    3> >(sed 's/^/ERR:/') 2> >(sed 's/^/TIME:/') > >(sed 's/^/OUT:/')

如果 fd 2 上的时间和 fd 3 上的时间更令人愉快err,因此我们交换它们,这很麻烦,因为没有直接的方法来交换两个文件描述符:

{ { { time -p sh -c 'echo out; echo 1>&2 err' 2>&3; } 3>&2 2>&4; } 4>&3; } 3> >(sed 's/^/TIME:/') 2> >(sed 's/^/ERR:/') > >(sed 's/^/OUT:/')

这显示了如何对命令的输出进行后处理,但如果您想捕获命令的输出及其时间,则需要更加努力。使用临时文件是一种解决方案。事实上,如果您需要捕获命令的标准错误及其标准输出,这是唯一可靠的解决方案。但除此之外,您可以捕获整个输出并利用time具有可预测格式的事实(如果您用于time -p获取POSIX 格式或 bash 特定的TIMEFORMAT变量)。

nl=$'\n'
output=$(TIMEFORMAT='%R %U %S %P'; mycommand)
set ${output##*$nl}; real_time=$1 user_time=$2 system_time=$3 cpu_percent=$4
output=${output%$nl*}

如果您只关心挂钟时间,那么date在之前和之后运行是一个简单的解决方案(如果由于加载外部命令所花费的额外时间而稍微不精确)。

答案4

在将所有以前的回复放在一起时,在 OSX 中

ProductName:    Mac OS X
ProductVersion: 10.11.6
BuildVersion:   15G31+

你可以这样做

microtime() {
    python -c 'import time; print time.time()'
}
compute() {
    local START=$(microtime)
    #$1 is command $2 are args
    local END=$(microtime)
    DIFF=$(echo "$END - $START" | bc)
    echo "$1\t$2\t$DIFF"
}

相关内容