bash中的时间戳算法

cmb*_*ley 5 bash awk date iso8601 unix-timestamp

假设我有两个日志文件(input.logoutput.log),格式如下:

2012-01-16T12:00:00 12345678
Run Code Online (Sandbox Code Playgroud)

第一个字段是处理时间戳,第二个字段是唯一 ID。我试图找到:

  1. input.log没有该 ID 对应记录的记录output.log
  2. 记录从input.log具有该ID的记录,在时间戳的差超过5秒

我有一个MySQL变通解决方案,但我希望删除数据库组件并使用 shell 脚本处理它。

我有以下内容,input.log如果output.log包含 ID ,则返回带有添加列的行:

join -a1 -j2 -o 0 1.1 2.1 <(sort -k2,2 input.log) <(sort -k2,2 output.log)
Run Code Online (Sandbox Code Playgroud)

示例输出:

10111 2012-01-16T10:00:00 2012-01-16T10:00:04
11562 2012-01-16T11:00:00 2012-01-16T11:00:10
97554 2012-01-16T09:00:00
Run Code Online (Sandbox Code Playgroud)

主要问题

既然我有了这些信息,我该如何计算两个时间戳之间的差异并丢弃相隔超过 5 秒的时间戳?我在处理 ISO 8601 时间戳时遇到了一些问题date(特别是T),并假设必须有更好的方法。

次要问题

有没有办法重新设计整个方法,例如变成单个awk脚本?我处理多个文件和为输出条件设置正确不等式的知识是这里的限制因素,因此是上述方法。

jay*_*ngh 5

如果你有GNU awk,那么你可以尝试这样的事情 -

gawk '
NR==FNR{a[$2]=$1;next} 
!($2 in a) {print $2,$1; next} 
($2 in a) {
  "date +%s -d " $1 | getline var1;
  "date +%s -d " a[$2] | getline var2;
  var3 = var2 - var1;
  if (var3 > 4) print $2, $1, a[$2]
}' output.log input.log
Run Code Online (Sandbox Code Playgroud)

测试:

[jaypal:~/Temp] cat input.log 
2012-01-16T09:00:00 9
2012-01-16T10:00:00 10
2012-01-16T11:00:00 11

[jaypal:~/Temp] cat output.log 
2012-01-16T10:00:04 10
2012-01-16T11:00:10 11
2012-01-16T12:00:00 12

[jaypal:~/Temp] gawk '
NR==FNR{a[$2]=$1;next} 
!($2 in a) {print $2,$1; next} 
($2 in a) {"date +%s -d " $1 | getline var1; "date +%s -d " a[$2] | getline var2;var3=var2-var1;if (var3>4) print $2,$1,a[$2] }' output.log input.log
9 2012-01-16T09:00:00
11 2012-01-16T11:00:00 2012-01-16T11:00:10
Run Code Online (Sandbox Code Playgroud)

解释:

  • NR==FNR{a[$2]=$1;next}

我们首先将 output.log 文件中的第一个字段存储在第二个字段索引的数组中。我们用来next阻止其他pattern{action}语句运行。使用NR==FNR允许我们完全读取output.log 文件。

  • !($2 in a) {print $2,$1; next}

一旦output.log 文件完成。我们从 input.log 文件开始。我们检查 input.log 文件中存在的任何第二个字段是否不存在于我们的数组(即 output.log 文件)中。如果找到我们打印它。我们继续此操作,直到打印出所有这些字段。

  • ($2 in a) {"date +%s -d " $1 | getline var1; "date +%s -d " a[$2] | getline var2; var3=var2-var1; if (var3 > 4) print $2,$1,a[$2] }

在此,我们查找两个文件中存在的字段。当我们找到这些字段时,我们需要输入逻辑来计算差异。我们使用系统命令来查找日期。现在系统命令默认打印到 STDOUT,我们无法控制它们。因此,我们通过管道传输输出并使用函数捕获输出awk getline并将其存储在变量(var1 和 var2)中。一旦两个日期都存储在变量中,我们就会进行差异并将其存储在 var3 中,如果发现 var3 > 4,我们会以您想要的格式打印它。