【问题标题】:Timestamp arithmetic in bashbash中的时间戳算术
【发布时间】:2012-01-17 00:45:40
【问题描述】:

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

2012-01-16T12:00:00 12345678

第一个字段是处理时间戳,第二个字段是唯一 ID。我正在寻找:

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

我有一个workaround solution with MySQL,但我希望删除数据库组件并使用 shell 脚本处理它。

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

join -a1 -j2 -o 0 1.1 2.1 <(sort -k2,2 input.log) <(sort -k2,2 output.log)

示例输出:

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

主要问题

现在我有了这些信息,我该如何计算这 2 个时间戳之间的差异并丢弃相隔 5 秒以上的时间戳?我在使用date(特别是T)处理ISO 8601 时间戳时遇到了一些问题,并假设一定有更好的方法。

次要问题

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

【问题讨论】:

  • 回到当我不得不对时差进行 awk 计算时,它跨越了日、月、年的界限,如果有一个免费赠品数据库来为我进行计算,我会杀了 ;-)。绝对可以用 awk 计算时间差异。在此处搜索我的一些早期帖子以获取一些想法。也不要对您当前的方法感到难过。 Unix 工具包管道哲学就是将您的问题分解为可解决的部分。您已经解决了一大块问题,而您只需要一个 awk 过滤器就可以完成它。进入下一个问题! (在 awk sub("T", " ", $2) &amp; $3 到 elim T 及时。祝你好运。
  • 如果您有 GNU 日期,您可以使用它来转换为 UNIX 时间,执行数学运算然后再转换回来。
  • 我已尝试在 awk 单行(大单行)中解决您的问题。让我知道这是否适合您。

标签: bash date awk unix-timestamp iso8601


【解决方案1】:

如果你有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

测试:

[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

说明:

  • 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 &gt; 4) print $2,$1,a[$2] }

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

【讨论】:

  • 我真的很喜欢这个。我有 getline 工作,但无法弄清楚 next 的正确用途。
  • 添加一条评论:它与用户未知的解决方案具有相同的问题,即 ISO 8601 日期字符串由于将T 误解为时区指示符而被错误地解析。对于我的用例,它不会出现问题,因为错误会被抵消,但这里值得一提。
  • 感谢@cbuckley 的反馈。老实说,我对bash 中的date 功能一点也不了解。但是,我会尽量记住这一点。
【解决方案2】:

这是我采用的解决方案:

cat input.log
2012-01-16T09:00:00 9
2012-01-16T10:00:00 10
2012-01-16T11:00:00 11

cat output.log
2012-01-16T10:00:04 10
2012-01-16T11:00:10 11
2012-01-16T12:00:00 12

sort -k2,2 input.log > input.sort
sort -k2,2 output.log > output.sort

join -a1 -j2 -o 0 1.1 2.1 input.sort output.sort | while read id i o; do
    if [ -n "$o" ]; then
        ot=$(date +%s -d "${o/T/ }")
        it=$(date +%s -d "${i/T/ }")
        [[ $it+5 -lt $ot ]] && echo $id $i $o
    else echo $id $i
    fi
done
11 2012-01-16T11:00:00 2012-01-16T11:00:10
9 2012-01-16T09:00:00

【讨论】:

    【解决方案3】:
    t1=2012-01-16T10:00:00
    t2=2012-01-16T10:00:04
    echo $(($(date -d $t1 +%s)-$(date -d $t2 +%s)))
    -4
    

    【讨论】:

    • 查看date -d "2012-01-16T10:00:00" 的输出,时间部分是 7 小时,因为 T 是 UTC-07:00 的区域指示符。它可能会持续发生,但可能会掩盖其他日期比较问题,因此需要更换。
    • 因此有什么替代品?我不明白你的问题。 t2=2012-01-16M10:00:04 屈服于 -68404,还是我明白了吗?
    • 我的意思是我的例子中的替换;你的应该是${t1/T/ }。在ISO 8601 中,T 指的是时间组件的开始,而不是区域指示符(由于我们所有的服务器都使用 UTC,因此日志时间戳中省略了它)。
    • 好吧 - 如果所有服务器都使用 UTC,为什么还要麻烦?
    • 何必纠结什么?无论服务器的时区如何,date 错误地解析上述日期字符串。值得庆幸的是,我正在计算差异,这掩盖了这个特定实例中的错误;但是实际的 Unix 时间戳操作数都是不正确的。 2012-01-16T10:00:00Z1326708000,而不是 1326682800
    猜你喜欢
    • 2017-10-31
    • 2011-07-25
    • 2016-09-16
    • 2010-10-25
    • 1970-01-01
    • 1970-01-01
    • 2020-05-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多