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
返回的时间应具有亚秒精度,但实际精度可能因平台而异。如果标准的C
gettimeofday()
系统调用在此平台上可用,那么它只返回值。否则,如果在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