如何在 bash 脚本中进行时间测量?

Sae*_*ati 5 bash function time

基于这个答案,为了测量我的 bash 脚本中的时间,我可以使用:

start_time="$(date -u +%s.%N)"
sleep 5
end_time="$(date -u +%s.%N)"

elapsed="$(bc <<<"$end_time-$start_time")"
echo "Total of $elapsed seconds elapsed for process"
Run Code Online (Sandbox Code Playgroud)

而且效果很好。然而,由于我有很多脚本文件,我很想简化和干燥代码。例如我想实现这样的代码:

. /time.sh

start_time=now
sleep 5
end_time=now

measure_time
Run Code Online (Sandbox Code Playgroud)

换句话说,我想要另一个名为time.sh可以包含在任何地方的脚本,并且它应该有两个功能。一种是更换"$(date -u +%s.%N)"零件,一种是更换"$(bc <<<"$end_time-$start_time")"零件。

我尝试创建这些函数,但后来我意识到在 shell 中,我们无法从函数返回值。我们只能返回数字。

有没有办法将上面的代码简化为下面的代码?

Qua*_*tal 5

在最新版本的 bash (5.0+) 中,有一个变量可以以微秒(6 个小数位)的精度给出时间。如果这对于您的使用来说足够精确,您可以尝试以下脚本:

#!/bin/bash --
time_diff(){ 
    local elapsed="$(bc <<<"${send}-${start}")"
    echo "Total of $elapsed seconds elapsed for process";
 }

start=$EPOCHREALTIME
sleep 5
end=$EPOCHREALTIME

time_diff

Run Code Online (Sandbox Code Playgroud)

该脚本获取时间值的速度比调用外部可执行文件 ( date) 执行相同操作的速度更快。


Jer*_*den 5

出什么问题了time ./script.sh

简单的例子:-

睡觉时间5

real    0m5.001s
user    0m0.001s
sys 0m0.000s
Run Code Online (Sandbox Code Playgroud)


bxm*_*bxm 2

从最简单的形式来看,这听起来就是您所追求的。

now(){
  date -u +%s.%N
}

measure_time(){
  local elapsed="$(bc <<<"$end_time-$start_time")"
  echo "Total of $elapsed seconds elapsed for process"
}

start_time="$(now)"
sleep 5
end_time="$(now)"

measure_time
Run Code Online (Sandbox Code Playgroud)

您可以使该now函数接受一个命名变量并调整该measure_time函数来处理该变量,但如果您的用例是一次跟踪一个进程,那么这将是一种不必要的复杂化。

话虽如此,这是朝这个方向的迭代。 startend是任意标签,因此如果您要跟踪多个事件,您可以将它们称为任何合适的名称。

stamp(){
  time[$1]="$(date -u +%s.%N)"
}

measure_time(){
  local elapsed="$(bc <<<"${time[$2]}-${time[$1]}")"
  echo "Total of $elapsed seconds elapsed for process"
}

declare -A time=()

stamp start
sleep 5
stamp end

measure_time start end
Run Code Online (Sandbox Code Playgroud)

编辑:

警告

正如 roaima 的答案中的数字所示,这不会是高精度,因为每个操作(特别是子 shell 和外部进程)都会将报告的超时填充几分之一秒。这对于多分钟的过程可能并不重要(在这种情况下为什么要测量纳秒?),但在较低的运行时间下会变得更加明显,甚至几乎毫无意义。尽管在我的测试中,与 roaima 的测试相比,问题并没有那么严重。这更取决于您使用该数据的目的。

另一个编辑:

为了回应 QuartzCrystal 的公正评论,这里有一个进一步的迭代,事实证明,它正在收敛于 roaima 的答案——可能表明他们处于“最佳”轨道上。

_stamp(){
  time[${1:?}]="$(date -u +%s.%N)"
}

_start() {
  _stamp "start${1:+_${1}}"
}

_end() {
  _stamp "end${1:+_${1}}"
}

measure_time(){
  local elapsed="$(bc <<<"${time[end${1:+_${1}}]}-${time[start${1:+_${1}}]}")"
  echo "Total of $elapsed seconds elapsed${1:+ for process ${1}}"
}

declare -A time=()

_start
sleep 5
_end

measure_time

_start foo
sleep 1
_start bar
sleep 2
_end foo
_end bar

measure_time foo
measure_time bar
Run Code Online (Sandbox Code Playgroud)