用于计算已用时间的Bash脚本

Mic*_*Mao 103 linux bash shell

我正在用bash编写一个脚本来计算执行命令所用的时间,考虑:

STARTTIME=$(date +%s)
#command block that takes time to complete...
#........
ENDTIME=$(date +%s)
echo "It takes $($ENDTIME - $STARTTIME) seconds to complete this task..."
Run Code Online (Sandbox Code Playgroud)

我想我的逻辑是正确的,但我最终得到以下打印输出:

"完成这项任务需要几秒钟......"

我的字符串评估有什么问题吗?

我相信bash变量是无类型的,如果bash中存在"字符串到整数"方法,我很乐意.

Lon*_*aut 129

我发现使用内部变量"$ SECONDS"非常干净

SECONDS=0 ; sleep 10 ; echo $SECONDS

  • 只有成功=) (9认同)
  • `$ SECONDS`确实适用于/ bin/bash.它不适用于/ bin/dash,Debian和Ubuntu中的默认shell. (3认同)
  • 该解决方案的缺点是它只能测量整秒,即如果您需要亚秒级精度则不可用。 (2认同)

Omn*_*ity 76

无论是$(())$[]将用于计算的算术运算的结果工作.你正在使用$()它只是取字符串并将其作为命令进行评估.这是一个微妙的区别.希望这可以帮助.

正如tink在对这个答案的评论中指出的那样,$[]已被弃用,$(())应该受到青睐.

  • 您可能希望交换这两个,因为bash 4.x man-page声明**$ []**已被弃用,将在未来版本中删除. (6认同)
  • 谢谢,我没有意识到. (2认同)

per*_*eal 50

您正尝试在ENDTIME命令中执行该数字.您还应该看到类似的错误1370306857: command not found.而是使用算术扩展:

echo "It takes $(($ENDTIME - $STARTTIME)) seconds to complete this task..."
Run Code Online (Sandbox Code Playgroud)

您还可以将命令保存在单独的脚本中commands.sh,并使用time命令:

time commands.sh
Run Code Online (Sandbox Code Playgroud)


gni*_*urf 25

您可以time在此处使用Bash的关键字和适当的格式字符串

TIMEFORMAT='It takes %R seconds to complete this task...'
time {
    #command block that takes time to complete...
    #........
 }
Run Code Online (Sandbox Code Playgroud)

这是参考文献所说的内容TIMEFORMAT:

此参数的值用作格式字符串,指定time 应如何显示以保留字为前缀的管道的计时信息.' %'字符引入了一个转义为时间值或其他信息的转义序列.逃逸序列及其含义如下; 括号表示可选部分.

%%

    A literal ‘%’.
%[p][l]R

    The elapsed time in seconds.
%[p][l]U

    The number of CPU seconds spent in user mode.
%[p][l]S

    The number of CPU seconds spent in system mode.
%P

    The CPU percentage, computed as (%U + %S) / %R. 
Run Code Online (Sandbox Code Playgroud)

可选p是指定精度的数字,小数点后的小数位数.值为0表示不输出小数点或小数.最多可以指定小数点后的三个位置; p大于3的值更改为3.如果未指定p,则使用值3.

可选项l指定MMmSS.FFs格式的更长格式,包括分钟.p的值确定是否包括分数.

如果未设置此变量,则Bash就像具有该值一样

$'\nreal\t%3lR\nuser\t%3lU\nsys\t%3lS'
Run Code Online (Sandbox Code Playgroud)

如果该值为null,则不显示任何计时信息.显示格式字符串时,将添加尾随换行符.


Mik*_*e Q 15

对于更大的数字,我们可能希望以更易读的格式打印。下面的示例与其他示例相同,但也以“人类”格式打印:

secs_to_human() {
    if [[ -z ${1} || ${1} -lt 60 ]] ;then
        min=0 ; secs="${1}"
    else
        time_mins=$(echo "scale=2; ${1}/60" | bc)
        min=$(echo ${time_mins} | cut -d'.' -f1)
        secs="0.$(echo ${time_mins} | cut -d'.' -f2)"
        secs=$(echo ${secs}*60|bc|awk '{print int($1+0.5)}')
    fi
    echo "Time Elapsed : ${min} minutes and ${secs} seconds."
}
Run Code Online (Sandbox Code Playgroud)

简单测试:

secs_to_human "300"
secs_to_human "305"
secs_to_human "59"
secs_to_human "60"
secs_to_human "660"
secs_to_human "3000"
Run Code Online (Sandbox Code Playgroud)

输出:

Time Elapsed : 5 minutes and 0 seconds.
Time Elapsed : 5 minutes and 5 seconds.
Time Elapsed : 0 minutes and 59 seconds.
Time Elapsed : 1 minutes and 0 seconds.
Time Elapsed : 11 minutes and 0 seconds.
Time Elapsed : 50 minutes and 0 seconds.
Run Code Online (Sandbox Code Playgroud)

要在其他帖子中描述的脚本中使用(捕获开始点,然后使用结束时间调用函数:

start=$(date +%s)
# << performs some task here >>
secs_to_human "$(($(date +%s) - ${start}))"
Run Code Online (Sandbox Code Playgroud)


Int*_*ror 7

这是 Mike Q 函数的单行替代方法:

secs_to_human() {
    echo "$(( ${1} / 3600 ))h $(( (${1} / 60) % 60 ))m $(( ${1} % 60 ))s"
}
Run Code Online (Sandbox Code Playgroud)

  • 将其与 Lon Kaut 的[答案](/sf/answers/2216476461/) 中的“SECONDS”结合起来,并记住 [$/${} 在算术变量上是不必要的](https://github.com/ koalaman/shellcheck/wiki/SC2004) 使代码如此短,甚至可以内联使用: `echo "$((SECONDS/3600))h $(((SECONDS/60)%60))m $((SECONDS% 60))s"` (3认同)

小智 6

请尝试以下代码:

start=$(date +'%s') && sleep 5 && echo "It took $(($(date +'%s') - $start)) seconds"
Run Code Online (Sandbox Code Playgroud)