我正在尝试找到一种将日志文件中的时间戳转换为 Unix 时间戳的方法。到目前为止我想出的命令如下:
awk -F'[' '{ print $2}' | awk -F']' '{cmd ="date \"+%s\" -d \""$1"\""; cmd | getline var; print var $2; close(cmd)}'
当原始时间戳包含 UTC 作为时区或未指定时区时,该命令有效。但是,当时区是其他值时,它会失败。例如,这有效:
$ entry="[08-May-2020 15:40:32 UTC] PHP Warning: Illegal string offset 'ID' in /home/example/public_html/wp-content/themes/example/functions.php on line 1290"
$ echo "$entry" | awk -F'[' '{ print $2}' | awk -F']' '{cmd="date \"+%s\" -d \""$1"\""; cmd | getline var; print var $2; close(cmd)}'
1588952432 PHP Warning: Illegal string offset 'ID' in /home/example/public_html/wp-content/themes/example/functions.php on line 1290
该命令在未指定时区时也有效:
$ entry="[08-May-2020 15:40:32] PHP Warning: Illegal string offset 'ID' in /home/example/public_html/wp-content/themes/example/functions.php on line 1290"
$ echo "$entry" | awk -F'[' '{ print $2}' | awk -F']' '{cmd="date \"+%s\" -d \""$1"\""; cmd | getline var; print var $2; close(cmd)}'
1588948832 PHP Warning: Illegal string offset 'ID' in /home/example/public_html/wp-content/themes/example/functions.php on line 1290
但是,当时区是时,Europe/London
它会失败:
$ entry="[08-May-2020 15:40:32 Europe/London] PHP Warning: Illegal string offset 'ID' in /home/example/public_html/wp-content/themes/example/functions.php on line 1290"
$ echo "$entry" | awk -F'[' '{ print $2}' | awk -F']' '{cmd="date \"+%s\" -d \""$1"\""; cmd | getline var; print var $2; close(cmd)}'
date: invalid date ‘08-May-2020 15:40:32 Europe/London’
PHP Warning: Illegal string offset 'ID' in /home/example/public_html/wp-content/themes/example/functions.php on line 1290
我真的不知道如何调试 awk 命令。我怀疑它可能不喜欢时区中的斜线,但这只是一个猜测。
答案1
date 接收 TZ 变量(并理解它)的方式非常棘手。该命令的工作原理:
$ date -d 'TZ="UTC" 08-May-2020 15:40:32' +"%s"
1588952432
以及来自 Olson 数据库的 TZ:
$ date -d 'TZ="Europe/London" 08-May-2020 15:40:32' +"%s"
1588948832
并注意纪元时间不同1588952432
和1588948832
。由于伦敦-1
和 UTC 存在一 (1) 小时的差异0
。
了解格式非常严格,首先是 TZ,所有内容都在单引号内,TZ 值也在双引号内。而且,如此严格,也相当脆弱。
因此,在数组中设置值(假设是 bash、ksh 或 zsh):
entry=(
"[08-May-2020 15:40:32 UTC] PHP Warning: Illegal string offset 'ID' in /home/example/public_html/wp-content/themes/example/functions.php on line 1290"
"[08-May-2020 15:40:32] PHP Warning: Illegal string offset 'ID' in /home/example/public_html/wp-content/themes/example/functions.php on line 1290"
"[08-May-2020 15:40:32 Europe/London] PHP Warning: Illegal string offset 'ID' in /home/example/public_html/wp-content/themes/example/functions.php on line 1290"
)
然后,我们可以使用 awk 获取日期中的所有值(请注意,一次调用 awk 时的 FS 不同(从技术上讲:GNU awk 或 nawk),并且由于时间字符串的元素数量不同而使用 split):
printf '%s\n' "${entry[@]}" | awk -F '[][]' '{
n=split($2, val, / /, sep);
cmd=sprintf("date +\"%%s\" -d '\''TZ=\"%s\" %s %s'\''",val[3],val[1],val[2]);
cmd | getline var; close(cmd);
print "["var"]"$3;
}'
[1588952432] PHP Warning: Illegal string offset 'ID' in /home/example/public_html/wp-content/themes/example/functions.php on line 1290
[1588952432] PHP Warning: Illegal string offset 'ID' in /home/example/public_html/wp-content/themes/example/functions.php on line 1290
[1588948832] PHP Warning: Illegal string offset 'ID' in /home/example/public_html/wp-content/themes/example/functions.php on line 1290
请注意,从技术上讲,一行如下:
if ( (rc=(cmd | getline var)) != 1){
print "error on calling the command date ",rc; exit
};
会捕获 getline 的一些错误(基本上 getline 无法从命令中获取输出),但 awk 无法报告也无法对命令中的错误号采取行动。如果需要的话,命令有责任中断执行。 awk 唯一做的事情(无论是否有错误)就是将 cmd 的 stderr 输出直接传递到它的 stderr。因此,您将在 awk 的 stderr 上看到该命令引发的任何注释(或错误)。如果需要,请务必检查并处理这些内容。如果没有,输出文件将悄无声息地损坏。你被警告了!。这似乎就是你所要求的。
不,awkdatetime()
无法理解 TZ 时间,更不能理解 Olson 数据库中的值。
答案2
@Isaac 走在正确的轨道上,请务必将他的答案保留为已接受的答案,因为它可能适合您的输入,但我会这样做以捕获输入不以预期字符串开头的情况[date+time]
,调用date
失败或失败,因此如果消息文本中时间戳后面getline
有 a 则调用成功,因此如果执行的任何部分失败,它会以失败退出状态退出:]
$ cat tst.awk
match($0,/\[[^]]+] /) {
dt = substr($0,RSTART+1,20)
tz = substr($0,RSTART+22,RLENGTH-24)
msg = substr($0,RSTART+RLENGTH)
cmd = sprintf("date -d \047TZ=\"%s\" %s\047 +\047%%s\047", tz, dt)
cmd | getline secs
close(cmd)
}
secs == "" {
printf "%s[%d]: failed to convert: \"%s\"\n", FILENAME, NR, $0 | "cat>&2"
exit 1
}
{ print secs, msg; secs="" }
例如,给定此输入文件(请注意最后两行 - 第一行在]
消息部分中有一个,第二行有一个无效日期):
$ cat file
[08-May-2020 15:40:32 UTC] PHP Warning: Illegal string offset 'ID' in /home/example/public_html/wp-content/themes/example/functions.php on line 1290"
[08-May-2020 15:40:32] PHP Warning: Illegal string offset 'ID' in /home/example/public_html/wp-content/themes/example/functions.php on line 1290
[08-May-2020 15:40:32 Europe/London] PHP Warning: Illegal string offset 'ID' in /home/example/public_html/wp-content/themes/example/functions.php on line 290
[08-May-2020 15:40:32 Europe/London] PHP Warning: array foo[] is bad, the sky is falling
[08-Bob-2020 15:40:32 Europe/London] PHP Warning: Illegal string offset 'ID' in /home/example/public_html/wp-content/themes/example/functions.php on line 290
$ awk -f tst.awk file
1588952432 PHP Warning: Illegal string offset 'ID' in /home/example/public_html/wp-content/themes/example/functions.php on line 1290"
1588952432 PHP Warning: Illegal string offset 'ID' in /home/example/public_html/wp-content/themes/example/functions.php on line 1290
1588948832 PHP Warning: Illegal string offset 'ID' in /home/example/public_html/wp-content/themes/example/functions.php on line 290
1588948832 PHP Warning: array foo[] is bad, the sky is falling
date: invalid date ‘TZ="Europe/London" 08-Bob-2020 15:40:32’
file[5]: failed to convert: "[08-Bob-2020 15:40:32 Europe/London] PHP Warning: Illegal string offset 'ID' in /home/example/public_html/wp-content/themes/example/functions.php on line 290"
$ echo "$?"
1
以失败状态退出的最后一部分很重要,因此您可以编写这样的脚本,awk 'script' file > tmp && mv tmp file
而不必担心 awk 输出会覆盖您的输入文件,即使它失败,或者您可以以其他方式测试结果awk 'script' file