Linux 用于计算经过时间的 Bash 脚本
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16908084/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Bash script to calculate time elapsed
提问by Michael Mao
I am writing a script in bash to calculate the time elapsed for the execution of my commands, consider:
我正在用 bash 编写一个脚本来计算执行我的命令所用的时间,请考虑:
STARTTIME=$(date +%s)
#command block that takes time to complete...
#........
ENDTIME=$(date +%s)
echo "It takes $($ENDTIME - $STARTTIME) seconds to complete this task..."
I guess my logic is correct however I end up with the following print out:
我想我的逻辑是正确的,但是我最终打印出以下内容:
"It takes seconds to complete this task..."
“完成这个任务需要几秒钟……”
Anything wrong with my string evaluation?
我的字符串评估有什么问题吗?
I believe bash variables are untyped, I would love if there is a "string to integer" method in bash nevertheless.
我相信 bash 变量是无类型的,如果 bash 中有一个“字符串到整数”的方法,我会很高兴。
采纳答案by OmnipotentEntity
Either $(())
or $[]
will work for computing the result of an arithmetic operation. You're using $()
which is simply taking the string and evaluating it as a command. It's a bit of a subtle distinction. Hope this helps.
无论是$(())
或$[]
将用于计算的算术运算的结果工作。您正在使用$()
which 只是将字符串作为命令进行评估。这是一个微妙的区别。希望这可以帮助。
As tink pointed out in the comments on this answer, $[]
is deprecated, and $(())
should be favored.
正如 tink 在对此答案的评论中指出的那样,$[]
已被弃用,$(())
应该受到青睐。
回答by perreal
You are trying to execute the number in the ENDTIME
as a command. You should also see an error like 1370306857: command not found
. Instead use the arithmetic expansion:
您正在尝试将中的数字ENDTIME
作为命令执行。您还应该看到类似1370306857: command not found
. 而是使用算术扩展:
echo "It takes $(($ENDTIME - $STARTTIME)) seconds to complete this task..."
You could also save the commands in a separate script, commands.sh
, and use time command:
您还可以将命令保存在单独的脚本中commands.sh
,并使用 time 命令:
time commands.sh
回答by Lynch
try using time with the elapsed seconds option:
尝试将 time 与 elapsed seconds 选项一起使用:
/usr/bin/time -f%e sleep 1
under bash.
/usr/bin/time -f%e sleep 1
在 bash 下。
or \time -f%e sleep 1
in interactive bash.
或\time -f%e sleep 1
在交互式 bash 中。
see the time man page:
请参阅时间手册页:
Users of the bash shell need to use an explicit path in order to run the external time command and not the shell builtin variant. On system where time is installed in /usr/bin, the first example would become /usr/bin/time wc /etc/hosts
bash shell 的用户需要使用显式路径才能运行外部时间命令而不是 shell 内置变体。在时间安装在 /usr/bin 的系统上,第一个示例将变为 /usr/bin/time wc /etc/hosts
and
和
FORMATTING THE OUTPUT
...
% A literal '%'.
e Elapsed real (wall clock) time used by the process, in
seconds.
回答by Bulmaro Herrera
Try the following code:
试试下面的代码:
start=$(date +'%s') && sleep 5 && echo "It took $(($(date +'%s') - $start)) seconds"
回答by gniourf_gniourf
You can use Bash's time
keyword here with an appropriate format string
您可以time
在此处使用 Bash 的关键字和适当的格式字符串
TIMEFORMAT='It takes %R seconds to complete this task...'
time {
#command block that takes time to complete...
#........
}
Here's what the reference says about TIMEFORMAT
:
The value of this parameter is used as a format string specifying how the timing information for pipelines prefixed with the
time
reserved word should be displayed. The ‘%
' character introduces an escape sequence that is expanded to a time value or other information. The escape sequences and their meanings are as follows; the braces denote optional portions.%% 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.
The optional pis a digit specifying the precision, the number of fractional digits after a decimal point. A value of 0 causes no decimal point or fraction to be output. At most three places after the decimal point may be specified; values of pgreater than 3 are changed to 3. If pis not specified, the value 3 is used.
The optional
l
specifies a longer format, including minutes, of the form MMmSS.FFs.The value of pdetermines whether or not the fraction is included.If this variable is not set, Bash acts as if it had the value
$'\nreal\t%3lR\nuser\t%3lU\nsys\t%3lS'
If the value is null, no timing information is displayed. A trailing newline is added when the format string is displayed.
此参数的值用作格式字符串,指定
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.
可选的p是一个指定精度的数字,小数点后的小数位数。值为 0 会导致不输出小数点或分数。最多可指定小数点后三位;大于 3的p值更改为 3。如果未指定p,则使用值 3。
可选
l
指定更长的格式,包括分钟,格式为MMmSS.FFs。p的值决定了是否包括分数。如果未设置此变量,则 Bash 就好像它具有该值一样
$'\nreal\t%3lR\nuser\t%3lU\nsys\t%3lS'
如果该值为空,则不显示计时信息。显示格式字符串时添加尾随换行符。
回答by Lon Kaut
I find it very clean to use the internal variable "$SECONDS"
我发现使用内部变量“$SECONDS”非常干净
SECONDS=0 ; sleep 10 ; echo $SECONDS
SECONDS=0 ; sleep 10 ; echo $SECONDS
回答by Rafa? Bia?as
start=$(date +%Y%m%d%H%M%S);
for x in {1..5};
do echo $x;
sleep 1; done;
end=$(date +%Y%m%d%H%M%S);
elapsed=$(($end-$start));
ftime=$(for((i=1;i<=$((${#end}-${#elapsed}));i++));
do echo -n "-";
done;
echo ${elapsed});
echo -e "Start : ${start}\nStop : ${end}\nElapsed: ${ftime}"
Start : 20171108005304
Stop : 20171108005310
Elapsed: -------------6
回答by Rafa? Bia?as
#!/bin/bash
time_elapsed(){
appstop=; appstart=
ss_strt=${appstart:12:2} ;ss_stop=${appstop:12:2}
mm_strt=${appstart:10:2} ;mm_stop=${appstop:10:2}
hh_strt=${appstart:8:2} ; hh_stop=${appstop:8:2}
dd_strt=${appstart:6:2} ; dd_stop=${appstop:6:2}
mh_strt=${appstart:4:2} ; mh_stop=${appstop:4:2}
yy_strt=${appstart:0:4} ; yy_stop=${appstop:0:4}
if [ "${ss_stop}" -lt "${ss_strt}" ]; then ss_stop=$((ss_stop+60)); mm_stop=$((mm_stop-1)); fi
if [ "${mm_stop}" -lt "0" ]; then mm_stop=$((mm_stop+60)); hh_stop=$((hh_stop-1)); fi
if [ "${mm_stop}" -lt "${mm_strt}" ]; then mm_stop=$((mm_stop+60)); hh_stop=$((hh_stop-1)); fi
if [ "${hh_stop}" -lt "0" ]; then hh_stop=$((hh_stop+24)); dd_stop=$((dd_stop-1)); fi
if [ "${hh_stop}" -lt "${hh_strt}" ]; then hh_stop=$((hh_stop+24)); dd_stop=$((dd_stop-1)); fi
if [ "${dd_stop}" -lt "0" ]; then dd_stop=$((dd_stop+$(mh_days $mh_stop $yy_stop))); mh_stop=$((mh_stop-1)); fi
if [ "${dd_stop}" -lt "${dd_strt}" ]; then dd_stop=$((dd_stop+$(mh_days $mh_stop $yy_stop))); mh_stop=$((mh_stop-1)); fi
if [ "${mh_stop}" -lt "0" ]; then mh_stop=$((mh_stop+12)); yy_stop=$((yy_stop-1)); fi
if [ "${mh_stop}" -lt "${mh_strt}" ]; then mh_stop=$((mh_stop+12)); yy_stop=$((yy_stop-1)); fi
ss_espd=$((10#${ss_stop}-10#${ss_strt})); if [ "${#ss_espd}" -le "1" ]; then ss_espd=$(for((i=1;i<=$((${#ss_stop}-${#ss_espd}));i++)); do echo -n "0"; done; echo ${ss_espd}); fi
mm_espd=$((10#${mm_stop}-10#${mm_strt})); if [ "${#mm_espd}" -le "1" ]; then mm_espd=$(for((i=1;i<=$((${#mm_stop}-${#mm_espd}));i++)); do echo -n "0"; done; echo ${mm_espd}); fi
hh_espd=$((10#${hh_stop}-10#${hh_strt})); if [ "${#hh_espd}" -le "1" ]; then hh_espd=$(for((i=1;i<=$((${#hh_stop}-${#hh_espd}));i++)); do echo -n "0"; done; echo ${hh_espd}); fi
dd_espd=$((10#${dd_stop}-10#${dd_strt})); if [ "${#dd_espd}" -le "1" ]; then dd_espd=$(for((i=1;i<=$((${#dd_stop}-${#dd_espd}));i++)); do echo -n "0"; done; echo ${dd_espd}); fi
mh_espd=$((10#${mh_stop}-10#${mh_strt})); if [ "${#mh_espd}" -le "1" ]; then mh_espd=$(for((i=1;i<=$((${#mh_stop}-${#mh_espd}));i++)); do echo -n "0"; done; echo ${mh_espd}); fi
yy_espd=$((10#${yy_stop}-10#${yy_strt})); if [ "${#yy_espd}" -le "1" ]; then yy_espd=$(for((i=1;i<=$((${#yy_stop}-${#yy_espd}));i++)); do echo -n "0"; done; echo ${yy_espd}); fi
echo -e "${yy_espd}-${mh_espd}-${dd_espd} ${hh_espd}:${mm_espd}:${ss_espd}"
#return $(echo -e "${yy_espd}-${mh_espd}-${dd_espd} ${hh_espd}:${mm_espd}:${ss_espd}")
}
mh_days(){
mh_stop=; yy_stop=; #also checks if it's leap year or not
case $mh_stop in
[1,3,5,7,8,10,12]) mh_stop=31
;;
2) (( !(yy_stop % 4) && (yy_stop % 100 || !(yy_stop % 400) ) )) && mh_stop=29 || mh_stop=28
;;
[4,6,9,11]) mh_stop=30
;;
esac
return ${mh_stop}
}
appstart=$(date +%Y%m%d%H%M%S); read -p "Wait some time, then press nay-key..." key; appstop=$(date +%Y%m%d%H%M%S); elapsed=$(time_elapsed $appstop $appstart); echo -e "Start...: ${appstart:0:4}-${appstart:4:2}-${appstart:6:2} ${appstart:8:2}:${appstart:10:2}:${appstart:12:2}\nStop....: ${appstop:0:4}-${appstop:4:2}-${appstop:6:2} ${appstop:8:2}:${appstop:10:2}:${appstop:12:2}\n$(printf '%0.1s' "="{1..30})\nElapsed.: ${elapsed}"
exit 0
-------------------------------------------- return
Wait some time, then press nay-key...
Start...: 2017-11-09 03:22:17
Stop....: 2017-11-09 03:22:18
==============================
Elapsed.: 0000-00-00 00:00:01
回答by Mike Q
For larger numbers we may want to print in a more readable format. The example below does same as other but also prints in "human" format:
对于更大的数字,我们可能希望以更易读的格式打印。下面的示例与其他示例相同,但也以“人类”格式打印:
secs_to_human() {
if [[ -z || -lt 60 ]] ;then
min=0 ; secs=""
else
time_mins=$(echo "scale=2; /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(+0.5)}')
fi
echo "Time Elapsed : ${min} minutes and ${secs} seconds."
}
Simple testing:
简单测试:
secs_to_human "300"
secs_to_human "305"
secs_to_human "59"
secs_to_human "60"
secs_to_human "660"
secs_to_human "3000"
Output:
输出:
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.
To use in a script as described in other posts (capture start point then call the function with the finish time:
要在其他帖子中描述的脚本中使用(捕获开始点,然后使用结束时间调用函数:
start=$(date +%s)
# << performs some task here >>
secs_to_human "$(($(date +%s) - ${start}))"
回答by Internal Server Error
This is a one-liner alternative to Mike Q's function:
这是 Mike Q 函数的单行替代方法:
secs_to_human() {
echo "$(( / 3600 ))h $(( ( / 60) % 60 ))m $(( % 60 ))s"
}