如何转换日志文件每行的初始时间戳
日志时间戳格式转换问题
需要将日志每行开头的时间戳转换为YYYY-MM-DD HH:MM:SS格式,示例日志及预期输出如下:
$ cat test.log [Tue Apr 9 03:32:21 2024] {cmd1} [Tue Apr 9 03:33:42 2024] {cmd2} [Tue Apr 9 03:35:51 2024] {cmd3} $ $ cat test.log | < How ?? > 2024-04-09 03:32:21 cmd1 2024-04-09 03:33:42 cmd2 2024-04-09 03:35:51 cmd3 $
已尝试但失败的方法
- 使用awk分割字段提取内容,但无法转换时间格式:
$ cat test.log | awk -F"[][{}]" '{print $2" "$4}' Tue Apr 9 03:32:21 2024 cmd1 Tue Apr 9 03:33:42 2024 cmd2 Tue Apr 9 03:35:51 2024 cmd3 $
- 使用awk的
strftime函数转换时返回epoch起始时间:
$ cat test.log | awk -F"[][{}]" '{print strftime("%F %T", $2)" "$4}' 1970-01-01 00:00:00 cmd1 1970-01-01 00:00:00 cmd2 1970-01-01 00:00:00 cmd3 $
- 通过
system调用date命令转换时出现无效日期错误:
$ echo "Tue Apr 9 03:32:21 2024" | awk '{print strftime("%F %T", system("date -d \"$0\" +\"%s\""))}' awk: cmd. line:1: warning: escape sequence `\%' treated as plain `%' date: invalid date 'sh' 1970-01-01 00:00:01 $
可行解决方案
方法1:awk结合date命令(正确传递参数)
通过getline捕获date命令的输出作为时间戳,修复之前的参数传递问题:
cat test.log | awk -F"[][{}]" '{ cmd = "date -d \"" $2 "\" +%s" cmd | getline timestamp close(cmd) print strftime("%F %T", timestamp) " " $4 }'
执行后输出:
2024-04-09 03:32:21 cmd1 2024-04-09 03:33:42 cmd2 2024-04-09 03:35:51 cmd3
方法2:纯awk实现(无需外部命令)
如果使用GNU awk,可利用mktime直接解析时间字符串:
cat test.log | awk -F"[][{}]" '{ split($2, t, / /) # 月份映射:Jan=1, Feb=2...Dec=12 m = (index("JanFebMarAprMayJunJulAugSepOctNovDec", t[2]) + 2)/3 timestamp = mktime(t[5] " " m " " t[3] " " t[4]) print strftime("%F %T", timestamp) " " $4 }'
该方法无需调用外部命令,执行效率更高。
方法3:sed结合date命令
用sed提取时间和命令后,通过循环调用date处理:
cat test.log | sed -E 's/\[(.*)\] \{([^}]+)\}/\1 \2/' | while read time cmd; do printf "%s %s\n" "$(date -d "$time" +"%F %T")" "$cmd" done
失败原因解析
- strftime直接用$2失败:
strftime需要的是数字类型的epoch时间戳,而$2是字符串格式的时间,无法被识别,因此返回0对应的epoch起始时间。 - system调用date错误:
system函数返回的是命令的退出状态码(成功为0,失败为非0),而非命令输出;同时之前的变量拼接有误,$0在双引号中不会被awk解析为变量,需用字符串拼接方式传递参数。
内容的提问来源于stack exchange,提问作者Susanta Dutta
相关产品推荐
相关产品推荐

