Linux shell获取时间和时间间隔(ms级别)

说明:在进行一些性能测试的时候,有时候我们希望能计算一个程序运行的时间,有时候可能会自己写一个shell脚本方便进行一些性能测试的控制(比如希望能运行N次取平均值等),总之,这其中有一个需求可能就是获取一个时间戳或时间差。

1. Linux shell获取时间的相关命令

time命令:获取一个程序的执行时间,可以获取到实际运行时间以及程序在用户态和内核态分别的时间,大部分的性能测试,可能只需要关注实际时间。

time命令的使用就很简单了,在原有的要运行的程序(可执行文件、脚本等任何可执行程序)之前加上time即可。

问题一:time命令的常用选项

使用time,常用的选项是:-f和-p。其中-f后面指定一个格式串,控制time的输出的格式,默认的time输出是real、user、sys三行以xmxxx.xxxs的格式输出,通过-f可以控制。

-p选项也是格式,表示使用posix标准的格式,主要的区别是显示的时间都是以s为单位的,具体关于格式的问题参考man time的帮助内容就知道了。

PS:-f选项没法工作?弄不清楚为何-f和-o等选项都无法工作,知道的请补充。(-p是工作的)

另一种控制格式的方法是设置TIMEFORMAT环境变量,具体参考man time可以知道这些格式控制符分别表示什么。举例如下:

#time pwd
/home/sgeng2
real 0m0.000s
user 0m0.000s
sys 0m0.000s
#export TIMEFORMAT="real time %E, user time %U,sys time %S"
#time pwd
/home/sgeng2
real time 0.000, user time 0.000,sys time 0.000
#time -p pwd
/home/sgeng2
real 0.00
user 0.00
sys 0.00
#
#time pwd
/home/sgeng2 real 0m0.000s
user 0m0.000s
sys 0m0.000s
#export TIMEFORMAT="real time %E, user time %U,sys time %S"
#time pwd
/home/sgeng2
real time 0.000, user time 0.000,sys time 0.000
#time -p pwd
/home/sgeng2
real 0.00
user 0.00
sys 0.00
#

PS:很奇怪,感觉time的有些格式和上面的选项一样,好像不完全工作,总之,关系不大,格式并不重要,一般使用-p以秒作为单位就足够了。

问题二:time命令的输出的问题

上面已经说到,好像-o选项并不工作,那么,我们就只能自己想办法了。有时候写脚本,就希望把time的结果输出到文件中,然后可能会根据time的输出进行一些处理,比如提取出real时间等。显然,大家能想到的是重定向了,至于重定向的使用这里显然不准备讨论(太复杂),只是提示一点:time命令的输出结果是输出到stderr的,不是stdout,所以进行重定向的时候要注意了。看懂下面的例子基本就能理解了:

#time pwd
/home/sgeng2
real 0m0.000s
user 0m0.000s
sys 0m0.000s
#time pwd > out.txt
real 0m0.000s
user 0m0.000s
sys 0m0.000s
#cat out.txt
/home/sgeng2
#time pwd 2> out.txt
/home/sgeng2
real 0m0.000s
user 0m0.000s
sys 0m0.000s
#cat out.txt
#(time pwd) 2> out.txt
/home/sgeng2
#cat out.txt
real 0m0.000s
user 0m0.000s
sys 0m0.000s
#(time pwd) >& out.txt
#cat out.txt
/home/sgeng2
real 0m0.000s
user 0m0.000s
sys 0m0.000s
#
#time pwd
/home/sgeng2 real 0m0.000s
user 0m0.000s
sys 0m0.000s
#time pwd > out.txt real 0m0.000s
user 0m0.000s
sys 0m0.000s
#cat out.txt
/home/sgeng2
#time pwd 2> out.txt
/home/sgeng2 real 0m0.000s
user 0m0.000s
sys 0m0.000s
#cat out.txt
#(time pwd) 2> out.txt
/home/sgeng2
#cat out.txt real 0m0.000s
user 0m0.000s
sys 0m0.000s
#(time pwd) >& out.txt
#cat out.txt
/home/sgeng2 real 0m0.000s
user 0m0.000s
sys 0m0.000s
#

PS:这里更多的是涉及到的和重定向相关的内容,所以不会详细分析每一个例子。说明的是注意time pwd 2> out.txt和(time pwd) 2> out.txt的区别,前面一个的含义是把pwd的结果stderr重定向到out.txt,相当于"time (pwd 2> out.txt)"的结果。

date命令

关于date命令的使用,百度一把一大堆,就不重复了,例如可以参考:http://xingfujie.blog.51cto.com/2791569/637223

这里只说明一下几个常见的问题:

问题一:date的%s和%N

date中有很多控制格式的,其中%s是获取当前时间距离1970-01-01 00:00:00 UTC的时间差。date的其它很多格式控制都是控制当前时间的输出格式而已,比如只输出时分秒,只输出年月日等等,其中%N也是这一类,%N输出的是当前时间的纳秒部分,由于date并没有毫秒等级别的输出,所以在秒以下的内容都属于纳秒部分。所以从这个角度说,date是可以很精确的,可以达到纳秒级别。

问题二:获取一个时间戳

有时候会使用时间戳,或者随机数,UUID这样的东西,百度一下也有相关文章(比如搜索”shell date随机数“等)。一般来说,可以用%s和%N组合的方式就没问题,同一秒内,两次运行%N肯定不会一样,所以%s和%N组合能得到一个唯一数。

#date +%s.%N
1337435374.969263560
#date +%s+%N
1337435377+310281496
#date +%s_%N
1337435381_209334510
#date +%s_%N
1337435383_169263078
#date +%s_%N
1337435383_830009679
#

PS:有时候可能希望用一个”唯一“的东西来对文件命名等,就可以加上时间戳了。

2. Linux shell获取时间差(使用date命令)

至于使用time命令,其本身就是获取一个时间差,但是显然,time只适用于一些简单的情况,因为后面的参数是可以执行的内容,有时候可能需要执行多条命令,用time就比较麻烦。

(1) 秒为单位

date获取的是”当前时间“,显然,两次运行date就可以得到一个时间差,理论上,可以使用很多格式来表示date的输出,从而计算时间差,但是,显然,最直接的方式就是使用%s了,这样直接就可以计算出一个时间差,不需要那么复杂的shell字符串处理了。如下:

  1. #start=$(date +%s) && sleep 2 && end=$(date +%s) && echo $(( $end - $start ))

  2. 2

  3. #start=$(date +%s) && sleep 3 && end=$(date +%s) && echo $(( $end - $start ))

  4. 3

  5. #

#start=$(date +%s) && sleep 2 && end=$(date +%s) && echo $(( $end - $start ))
2
#start=$(date +%s) && sleep 3 && end=$(date +%s) && echo $(( $end - $start ))
3
#

当然,这里是在terminal中测试的,所以用&&连续执行这些命令,对于脚本,一行一行的写就很好了。。。。

  1. start=$(date +%s)

  2. ...what to do for timing...

  3. end=$(date +%s)

  4. time=$(( $end - $start ))

  5. echo $time

start=$(date +%s)
...what to do for timing...
end=$(date +%s)
time=$(( $end - $start ))
echo $time

(2) ms为单位

更多的性能测试等场合获取时间差,有可能希望精确到ms。事实上,使用date是可以达到ms的。直接上代码吧。

  1. #! /bin/bash

  2. #filename: test.sh

  3. # arg1=start, arg2=end, format: %s.%N

  4. function getTiming() {

  5. start=$1

  6. end=$2

  7. start_s=$(echo $start | cut -d '.' -f 1)

  8. start_ns=$(echo $start | cut -d '.' -f 2)

  9. end_s=$(echo $end | cut -d '.' -f 1)

  10. end_ns=$(echo $end | cut -d '.' -f 2)

  11. # for debug..

  12. #    echo $start

  13. #    echo $end

  14. time=$(( ( 10#$end_s - 10#$start_s ) * 1000 + ( 10#$end_ns / 1000000 - 10#$start_ns / 1000000 ) ))

  15. echo "$time ms"

  16. }

  17. echo "This is only a test to get a ms level time duration..."

  18. start=$(date +%s.%N)

  19. ls >& /dev/null    # hey, be quite, do not output to console....

  20. end=$(date +%s.%N)

  21. getTiming $start $end

#! /bin/bash
#filename: test.sh # arg1=start, arg2=end, format: %s.%N
function getTiming() {
start=$1
end=$2 start_s=$(echo $start | cut -d '.' -f 1)
start_ns=$(echo $start | cut -d '.' -f 2)
end_s=$(echo $end | cut -d '.' -f 1)
end_ns=$(echo $end | cut -d '.' -f 2) # for debug..
# echo $start
# echo $end time=$(( ( 10#$end_s - 10#$start_s ) * 1000 + ( 10#$end_ns / 1000000 - 10#$start_ns / 1000000 ) )) echo "$time ms"
} echo "This is only a test to get a ms level time duration..."
start=$(date +%s.%N)
ls >& /dev/null # hey, be quite, do not output to console....
end=$(date +%s.%N) getTiming $start $end

PS:这个代码是一个简单的测试,可以获取到ls命令执行的时间,相信其执行时间已经够短了,如果你需要获取的时间差在ms以下,相信你不会使用shell了,嘿嘿,自然要靠C去弄了。

结果如下:

  1. #./test.sh

  2. This is only a test to get a ms level time duration...

  3. 3 ms

  4. #./test.sh

  5. This is only a test to get a ms level time duration...

  6. 2 ms

  7. #./test.sh

  8. This is only a test to get a ms level time duration...

  9. 2 ms

  10. #

#./test.sh
This is only a test to get a ms level time duration...
3 ms
#./test.sh
This is only a test to get a ms level time duration...
2 ms
#./test.sh
This is only a test to get a ms level time duration...
2 ms
#

还满意吧,能获取到这么短的时间。当然,理论上可以获取到以ns为单位的时间差,但是,个人觉得用shell去弄这么小的时间差,你觉得准确么。。。

说明:

上面的代码的思路,其实很简单了,%s为距离标准时间的秒数,%N为当前时间的秒以下的部分,那么显然,%s和%N就表示了当前时间的完整时间戳,两个时间戳就差值就是时间差,问题就是如何处理的问题,大概就是:先使用%s.%N的格式获取到start和end时间,然后利用cut命令从start和end中获取到“.“前面的秒的部分和后面的纳秒的部分(说明:这里的在%s和%N之间插入点,只是作为分隔的作用,任何可能的字符都是可以的,只要能被cut分开就行);然后,用秒的部分相减,得到秒的差值,转换为毫秒的差值;然后,把纳秒的部分转换为毫秒之后求差值(可能为负数);最后,两个差值相加就是真正的以毫秒为单位的差值了。很容易理解,关键是cut的使用,对于shell高手来说,应该有很多方法可以对字符串提取,但是对于我这样的非shell高手,要自己用awk或sed什么的写一个提取的正则,还是很有难度,还好找到了cut命令,能很容易的对这种字符串进行提取。所以:这里的方法仅供参考。。。

关于代码中的“10#”,这是表示后面的数是10进制的数字,之所以需要这个是因为这里的纳秒的前面是以0开头的,shell中好像以0开头会默认认为是八进制,导致运行报错,总之,百度一下就找到了原因,这里就索性把所有的数字都加上了10#,表示都是10进制。

shell获取时间的相关命令的更多相关文章

  1. linux中用shell获取时间,日期

    linux中用shell获取昨天.明天或多天前的日期:在Linux中对man date -d 参数说的比较模糊,以下举例进一步说明:# -d, --date=STRING display time d ...

  2. linux在shell date获取时间的相关操作

    获得当天的日期 date +%Y-%m-%d 输出: 2011-07-28 将当前日期赋值给DATE变量DATE=$(date +%Y%m%d) 有时候我们需要使用今天之前或者往后的日期,这时可以使用 ...

  3. linux shell获取时间

    获得当天的日期 date +%Y-%m-%d 输出: 2011-07-28 将当前日期赋值给DATE变量DATE=$(date +%Y%m%d) 有时候我们需要使用今天之前或者往后的日期,这时可以使用 ...

  4. shell 获取时间

    获取当前时间 t=$(date +"%Y-%m-%d %H-%M-%S") echo $t 获取前一天的当前时间 time=$(date -d "-1 day" ...

  5. Shell获取时间,日期,上月,当月,下月

    #当前日期 $ date +%F #当前时间$ date +"%F %H:%M:%S" #昨日$ date -d yesterday +%F #上一个月 $ date -d &qu ...

  6. Shell编程基础教程5--文本过滤、正则表达式、相关命令

    5.文本过滤.正则表达式.相关命令    5.1.正则表达式(什么是正则表达式?正则表达式怎么进行匹配?常用命令)        简介:            一种用来描述文本模式的特殊语法      ...

  7. [ SHELL编程 ] 编程常用的ORACLE相关命令

    本文主要描述shell编程中常用的Oracle相关命令. 1.sqlplus -L/-S参数 sqlplus -L user/password #-L参数表示用户只尝试登录一次, 而不是在出错时再次提 ...

  8. adb & adb shell 相关命令

    在Mac上配置adb命令 在Mac OS中使用adb命令时,应进行变量配置,步骤如下: 一.终端中输入 cd ~ 二.输入touch .bash_profile 回车 touch:如果没有,则创建文件 ...

  9. linux在shell中获取时间

    linux在shell中获取时间 获得当天的日期 date +%Y-%m-%d 输出: 2011-07-28 将当前日期赋值给DATE变量DATE=$(date +%Y%m%d) 有时候我们需要使用今 ...

随机推荐

  1. Enabling Remote Errors in SSRS

    January 18, 2011 By default the remote errors property in SQL Server Reporting Services is set to fa ...

  2. java 基础解析

    http://www.cnblogs.com/-new/tag/java%E5%9F%BA%E7%A1%80%E8%A7%A3%E6%9E%90/

  3. python网络编程--socket,网络协议,TCP

    一. 客户端/服务端架构(用到网络通信的地方) 我们使用qq.微信和别人聊天,通过浏览器来浏览页面.看京东的网站,通过优酷.快播(此处只是怀念一下)看片片啥的等等,通过无线打印机来打印一个word文档 ...

  4. markdown字体或者图片居中

    1.图片居中实例: 图片居中效果: 2.文字居中实例: 文字居中效果: 你的名字

  5. 打开SQL Server2000企业管理器时候提示“MMC 无法创建管理单元 ”

    今天上午在打开SQL Server 2000 企业管理器时候提示“MMC 无法创建管理单元”错误.

  6. mysql 赋给用户远程权限 grant all privileges on

    我配置了权限 就可以在Windows下访问我虚拟机中的数据库了 来源:http://blog.csdn.net/louisliaoxh/article/details/52767209 登录: 在本机 ...

  7. POJ 2196

    #include <iostream> using namespace std; int sum_10; int sum_12; int sum_16; int fun_10(int nu ...

  8. 2016级算法期末上机-I.难题·ModricWang's Fight with DDLs III

    1126 ModricWang's Fight with DDLs III 思路 由于题目中已经说明了时间经过了正无穷,因此初始位置是不重要的,并且每条边.每个点的地位是均等的.因此到达每个点的概率就 ...

  9. Spring Security 入门

    一.Spring Security简介 Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架.它提供了一组可以在Spring应用上下文中配 ...

  10. python学习,day4:装饰器的使用示例2

    这个例子比较复杂 # coding=utf-8 # Author: RyAn Bi user,passwd = ' #输入用户名密码 def auth(auth_type): #装饰器第一层,确定鉴权 ...