Awk 使用小数秒创建时间戳
Awk 使用小数秒创建时间戳,awk,timestamp,strftime,Awk,Timestamp,Strftime,awk可以使用strftime函数生成时间戳,例如 $ awk 'BEGIN {print strftime("%Y/%m/%d %H:%M:%S")}' 2019/03/26 08:50:42 但我需要一个分数秒的时间戳,最好是纳秒gnu日期可以使用%N元素执行此操作: $ date "+%Y/%m/%d %H:%M:%S.%N" 2019/03/26 08:52:32.753019800 但是与调用strftime相比,从awk中调用date效率相对较低,而且我需要高性能,因为我正在使用
awk
可以使用strftime函数生成时间戳,例如
$ awk 'BEGIN {print strftime("%Y/%m/%d %H:%M:%S")}'
2019/03/26 08:50:42
但我需要一个分数秒的时间戳,最好是纳秒<代码>gnu日期可以使用%N
元素执行此操作:
$ date "+%Y/%m/%d %H:%M:%S.%N"
2019/03/26 08:52:32.753019800
但是与调用strftime
相比,从awk
中调用date
效率相对较低,而且我需要高性能,因为我正在使用awk
处理许多大文件,并且在处理文件时需要生成许多时间戳。有没有一种方法可以使awk
有效地生成包含小数秒的时间戳(理想情况下是纳秒,但可以接受毫秒)
添加一个我正在尝试执行的示例:
awk -v logFile="$logFile" -v outputFile="$outputFile" '
BEGIN {
print "[" strftime("%Y%m%d %H%M%S") "] Starting to process " FILENAME "." >> logFile
}
{
data[$1] += $2
}
END {
print "[" strftime("%Y%m%d %H%M%S") "] Processed " NR " records." >> logFile
for (id in data) {
print id ": " data[id] >> outputFile
}
}
' oneOfManyLargeFiles
如果您在Linux上,可以使用
/proc/uptime
:
$ cat /proc/uptime
123970.49 354146.84
要获得几厘米秒(第一个值是正常运行时间)并计算开始时间和发生事件时间之间的时间差:
$ while true ; do echo ping ; sleep 0.989 ; done | # yes | awk got confusing
awk '
function get_uptime( a, line) {
if((getline line < "/proc/uptime") > 0)
split(line,a," ")
close("/proc/uptime")
return a[1]
}
BEGIN {
basetime=get_uptime()
}
{
if(!wut) # define here the cause
print get_uptime()-basetime # calculate time difference
}'
如果您确实需要亚秒计时,则任何对外部命令(如
date
)的调用或读取外部系统文件(如/proc/uptime
或/proc/rct
)都无法达到亚秒精度的目的。这两种情况都需要大量资源来检索请求的信息(即时间)
因为OP已经使用了GNUAWK,所以可以使用动态扩展。动态扩展是通过实现用C或C++编写的新功能并用GAWK动态加载它们来向AWK添加新功能的一种方式。如何编写这些函数在中有详细说明
幸运的是,GNUAWK4.2.1附带了一组默认的动态库,可以随意加载。其中一个库是具有两个简单函数的时间库:
时间=gettimeofday()
以浮点值形式返回自1970-01-01 UTC以来经过的时间(以秒为单位)。如果时间在此平台上不可用,请返回-1
并设置ERRNO
返回的时间应具有亚秒精度,但实际精度可能因平台而异。如果标准的Cgettimeofday()
系统调用在此平台上可用,那么它只返回值。否则,如果在MS Windows上,它将尝试使用GetSystemTimeAsFileTime()
结果=睡眠(秒)
尝试睡眠秒
秒。如果seconds
为负值,或者尝试睡眠失败,则返回-1
并设置ERRNO
。否则,在睡眠指定时间后返回零。请注意,秒可能是浮点(非整数)值。实现细节:根据平台可用性,此函数尝试使用nanosleep()
或select()
来实现延迟
来源:
现在可以以一种非常简单的方式调用此函数:
awk '@load "time"; BEGIN{printf "%.6f", gettimeofday()}'
1553637193.575861
为了证明此方法比更经典的实现更快,我使用gettimeofday()
对所有3个实现进行了计时:
虽然很明显,curtime()
在加载外部二进制文件时速度最慢,但看到awk在处理额外的外部/proc/文件时速度惊人还是相当惊人的。事实上,分秒、厘米秒或毫秒会有所帮助,因为纳秒可能有点极端。但是我正在打印时间戳和到目前为止已经处理的数据摘要,亚秒级的粒度在监控过程中非常有用。如果你正在处理一个大文件,你真的认为知道你处理它的时间是123.124秒还是124秒有关吗?这根本没有任何意义。另外,您可能对unix命令time
感兴趣。这似乎正是你感兴趣的。而且,这个问题的任何答案都没有意义。你需要一个尽可能精确的时间来了解你的处理速度。通过在awk中调用date
,您可以通过执行两个系统调用来降低速度。通过打开/proc/uptime
allone,您已经浪费了2毫秒。如果您的任务确实需要亚秒精度,那么时间应该不够好。不是所有的文件都很大,而且许多文件都在不到一秒钟的时间内处理。此外,特定代码有点做作,以提供一个简单、具体的示例。因此,是的,当它将事件写入日志时,需要知道点awk
在什么位置,直到小数秒。我从回答和评论中看到的是,awk不能用内部函数实现这一点。内部函数,例如strftime,只能获得秒的粒度。@EdMorton,感谢您的基准测试。看来我认为调用外部命令的速度较慢的假设可能不正确。基准程序中的一些函数调用不正确:gettimeofday
应该是gettimeofday
。此外,一些早期版本的GNU awk具有可加载的time
库。至少4.1.4似乎有。该功能似乎是在2012年添加的:为什么不把line
也作为get_-uptime()
的参数呢?@jarno这只是一个POC,但我看不出有什么理由不添加,除了getline
和close
需要在两个位置,函数get_-uptime()
将有点失去意义。不,但它会使line
成为像a
那样的局部变量,如果这很重要的话。@jarno哦,是的,没错。未经测试固定:D谢谢。
awk '@load "time"; BEGIN{printf "%.6f", gettimeofday()}'
1553637193.575861
awk '@load "time"
function get_uptime( a) {
if((getline line < "/proc/uptime") > 0)
split(line,a," ")
close("/proc/uptime")
return a[1]
}
function curtime( cmd, line, time) {
cmd = "date \047+%Y/%m/%d %H:%M:%S.%N\047"
if ( (cmd | getline line) > 0 ) {
time = line
}
else {
print "Error: " cmd " failed" | "cat>&2"
}
close(cmd)
return time
}
BEGIN{
t1=getimeofday(); curtime(); t2=gettimeofday();
print "curtime()",t2-t1
t1=getimeofday(); get_uptime(); t2=gettimeofday();
print "get_uptime()",t2-t1
t1=getimeofday(); gettimeofday(); t2=gettimeofday();
print "gettimeofday()",t2-t1
}'
curtime() 0.00519109
get_uptime() 7.98702e-05
gettimeofday() 9.53674e-07