基于这答案,要测量我的 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"
而且效果很好。然而,由于我有很多脚本文件,我很想简化和干燥代码。例如我想实现这样的代码:
. /time.sh
start_time=now
sleep 5
end_time=now
measure_time
换句话说,我想要另一个名为time.sh
可以包含在任何地方的脚本,并且它应该有两个功能。一种是更换"$(date -u +%s.%N)"
零件,一种是更换"$(bc <<<"$end_time-$start_time")"
零件。
我尝试创建这些函数,但后来我意识到在 shell 中,我们无法从函数返回值。我们只能返回数字。
有没有办法将上面的代码简化为下面的代码?
答案1
出什么问题了time ./script.sh
?
简单的例子:-
睡觉时间5
real 0m5.001s
user 0m0.001s
sys 0m0.000s
答案2
在最新版本的 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
该脚本获取时间值的速度比调用外部可执行文件 ( date
) 执行相同操作的速度更快。
答案3
从最简单的形式来看,这听起来就像您所追求的。
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
您可以使该now
函数接受一个命名变量并调整该measure_time
函数来处理该变量,但如果您的用例是一次跟踪一个进程,那么这将是一种不必要的复杂化。
话虽如此,这是朝这个方向的迭代。 start
和end
是任意标签,因此如果您要跟踪多个事件,您可以将它们称为任何合适的名称。
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
编辑:
警告
正如 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
答案4
这是一个需要关联数组的版本(bash
等)
放在一个例子中timers.sh
#!/bin/bash
########################################################################
declare -A _timers
# Declare and start a timer. Optional name
startTimer() {
_timers[${1:-_}_s]=$(date -u +'%s.%N')
}
# End a timer. Optional name
endTimer() {
_timers[${1:-_}_e]=$(date -u +'%s.%N')
}
# Report on the duration of a timer. Optional name
diffTimer() {
local s=${_timers[${1:-_}_s]} e=${_timers[${1:-_}_e]}
bc <<< "${e:-$(date -u +'%s.%N')} - ${s:-0}"
}
主要代码
#!/bin/bash
. timers.sh
startTimer
sleep 2
startTimer sub
sleep 0.1
endTimer sub
endTimer
echo "Elapsed $(diffTimer) and for sub $(diffTimer sub)"
输出
Elapsed 2.321831200 and for sub .183521000
如果没有参数,函数将作用于默认计时器。否则,它们将按照指定的计时器进行操作。如果不调用startTimer
或endTimer
使用默认值0
和现在被使用。定时器存储在全局关联数组中_timers[]