我有一个从未轮换过的服务的日志文件。现在我想将此日志文件拆分为单独的文件,每个月一个。大多数行都以括号中的 unix 时间戳开头,但是有些日志消息跨越多行(来自 的输出dig
),需要抓取。此外,多行消息后带有时间戳的下一行不一定来自同一个月。如下例所示。
1700653509 = Wed 22 Nov 12:45:09 CET 2023
1700798246 = Fri 24 Nov 04:57:26 CET 2023
1701385200 = Fri 1 Dec 00:00:00 CET 2023
[1700653509] unbound[499:0] debug: module config: "subnetcache validator iterator"
[1700798246] unbound[1506:0] info: incoming scrubbed packet: ;; ->>HEADER<<- opcode: QUERY, rcode: NOERROR, id: 0
;; flags: qr aa ; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
chat.cdn.whatsapp.net. IN A
;; ANSWER SECTION:
chat.cdn.whatsapp.net. 60 IN A 157.240.252.61
;; AUTHORITY SECTION:
;; ADDITIONAL SECTION:
;; MSG SIZE rcvd: 55
[1701385200] unbound[1506:0] debug: iter_handle processing q with state QUERY RESPONSE STATE
我的第一个方法是定义最小值和最大值(一个月的第一秒和最后一秒),并检查行中的时间戳是否符合该范围。如果是,则将其写入新日志文件并继续。我需要这种方法,因为日志文件中并非存在一个月的每个第一秒或最后一秒。
像这样:
for YEAR in {2023..2024}; do
for MONTH in {1..12}; do
# Calculate first and last second of each month
FIRST_SECOND="$(date -d "$(date +"$YEAR"/"$MONTH"/01)" "+%s")"
LAST_SECOND="$(date -d "$(date +"$YEAR"/"$MONTH"/01) + 1 month - 1 second" "+%s")"`
awk -F'[\\[\\]]' -v MIN="${FIRST_SECOND}" -v MAX="${LAST_SECOND}" '{if($2 >= MIN && $2 <= MAX) print}' unbound.log >> "unbound-$YEAR-$MONTH.log
done;
done
然后我遇到了多行消息并遇到了障碍。
基本上,我现在需要的是某种“抓取所有匹配和不匹配的行,直到第一个值大于 MAX”。我想到获取第一个和最后一个匹配的行号,然后简单地使用它们。但是我又遇到了多行消息的相同问题。
有什么想法吗?
编辑:根据已接受的答案,我最终得到了这个。我将文件名更改为 unbound-YYYY-MM 而不是 MM-YYYY,并在关闭每个文件后对其进行 gzip 压缩。
awk '
$1 ~ /^\[[0-9]+]$/ {
f = "unbound-" strftime("%Y-%m", substr($1, 2, length($1)-2)) ".log"
if (f != prev) {
if (prev) system("gzip " prev)
close(prev)
prev = f
}
}
{
print > f
}
END {
if (prev) system("gzip " prev)
}' unbound.log
使用 GNU
awk
(forstrftime
):对于第一个字段为 a 的每一行
[timestamp]
(即与正则表达式匹配^\[[0-9]+]$
),我们使用substr
和length
提取timestamp
,strftime
将其转换为YYYY-mm
字符串并分配"unbound-YYYY-mm.log"
给变量f
。在适用于所有行的第二个块中,我们打印文件 中的当前行f
。注意:与 shell 重定向相反,在 中awk
,print > FILE
附加到FILE
。编辑:正如 Ed Morton 所建议的,如果文件总数很大,则在完成操作后关闭每个文件应该会显著提高性能。
if (f != prev) close(f); prev = f
已添加。Ed 还指出,]
在正则表达式中转义最后一个字符是无用的(并且根据 POSIX 未定义的行为)。已删除反斜杠。我将按照以下方式利用
RS
GNU 的内置变量AWK
,考虑简化的示例,让file.txt
内容为然后
創造
file202311.txt
持續并
file202312.txt
持有解释:我告诉 GNU
AWK
,行分隔符是换行符,后跟左方括号,并且一连串数字构成字段,然后对于每一行,我准备根据它是否是第一行来打印什么,在后一种情况下,我们需要在前面添加左方括号,然后我将其输出到基于时间戳命名的文件中。(在 GNU Awk 5.1.0 中测试)