![从 UNIX 上的巨大日志文件中获取信息的快速方法](https://linux22.com/image/10278/%E4%BB%8E%20UNIX%20%E4%B8%8A%E7%9A%84%E5%B7%A8%E5%A4%A7%E6%97%A5%E5%BF%97%E6%96%87%E4%BB%B6%E4%B8%AD%E8%8E%B7%E5%8F%96%E4%BF%A1%E6%81%AF%E7%9A%84%E5%BF%AB%E9%80%9F%E6%96%B9%E6%B3%95.png)
我有一个 6 GB 的应用程序日志文件。日志具有以下格式(缩短)
[...]
timestamp;hostname;sessionid-ABC;type=m
timestamp;hostname;sessionid-ABC;set_to_TRUE
[...]
timestamp;hostname;sessionid-HHH;type=m
timestamp;hostname;sessionid-HHH;set_to_FALSE
[...]
timestamp;hostname;sessionid-ZZZ;type=m
timestamp;hostname;sessionid-ZZZ;set_to_FALSE
[...]
timestamp;hostname;sessionid-WWW;type=s
timestamp;hostname;sessionid-WWW;set_to_TRUE
除了这两行之外,我还有很多会议。我需要找出与type=m
和相关的所有会话set_to_TRUE
我的第一次尝试是 grep 所有 sessionIDtype=m
并将其写入文件中。然后通过大日志文件和 grep 循环文件中的每一行(每行 1 个 sessionID)sessionID;set_to_TRUE
这种方法需要花费大量时间。谁能给我一个提示,以更好更快的方式解决这个问题?
答案1
如果每个会话都有一个对应的type
and 是set_to
或者TRUE
,FALSE
那么您可以使用sed
and 范围来执行此操作:
sed '/type=m/,/set_to_/!d;/set_to_TRUE$/!d;s/.*\(sessionid-.*\);.*/\1/' infile
这将删除不在/type=m/,/set_to_/
范围内的所有行。它还删除那些范围内不以 结尾的行set_to_TRUE
。sessionid
然后从剩余行(如果有)中提取。
或者,
sed -n '/type=/h;/set_to_TRUE$/{
x;s/.*\(sessionid-.*\);type=m$/\1/p
}' infile
应该打印相同的。
后者的工作原理是在每条匹配的行上覆盖保持缓冲区type=
然后,在每条匹配的行上set_to_TRUE
,交换缓冲区并尝试替换 - 即sessionid
从以 结尾的行中提取type=m
- 如果成功,则打印结果p
。否则,由于通过 禁用自动打印,因此不会发生任何事情-n
。
上面假设您的行中没有尾随空格。
答案2
使用这个awk
命令:
awk -F";" '/type=m/{flag=$3;next} /set_to_TRUE/ && ($3==flag)' infile.txt
如果两个 sessionID 相同且所需条件也相同,则它将匹配。
timestamp;hostname;sessionid-ABC;set_to_TRUE
上面将打印整行,您可以通过添加来仅打印所需的列,print $3
以便只有 sessionID,如下所示:
awk -F";" '/type=m/{flag=$3;next} /set_to_TRUE/ && ($3==flag){print $3}' infile.txt
答案3
使用 grep 可以很容易地完成:
grep -E "(type=|set_to_)" file.txt | grep -A 1 "type=m" | grep -B 1 "set_to_TRUE" > file1.txt &
把它放在后台,喝杯咖啡,让它完成。不确定“awk”或“sed”是否会更快。6GB 对于纯文本来说太多了,这就是为什么无论如何尝试这样做都会花费很长时间。
无论如何,一旦您按 Enter 或输入另一个命令,您就会在控制台中看到它何时完成:
[1]+ Done grep --color=auto -E '(type=|set_to_)' file.txt | grep --color=auto -A 1 "type=m" | grep --color=auto -B 1 "set_to_TRUE" > file1.txt
答案4
awk -F';' '/type=m/ { seen[$3]=1 };
/set_to_TRUE/ && seen[$3] { print $3 ; delete seen[$3] };
/set_to_FALSE/ && seen[$3] { delete seen[$3] }' logfile.txt
这类似于αГsнιn 的回答,但它不是仅使用单个变量 ( flag
),而是使用数组 ( seen
) 来跟踪它看到的匹配的会话 ID type=m
。
type=m
这意味着,即使在任何会话的线路的瞄准type=m
和该会话的线路的瞄准之间存在不同会话的其他线路,它也可以工作set_to_
。
为了最大限度地减少脚本的内存需求,它会在看到匹配的或seen
时立即删除给定会话 ID 的数组元素。set_to_TRUE
set_to_FALSE
注意:上面的脚本仅打印匹配的会话 ID。如果你想打印实际的type=m
和set_to_TRUE
行,awk 脚本将是:
awk -F';' '/type=m/ { seen[$3]=$0 };
/set_to_TRUE/ && seen[$3] { print seen[$3]"\n"$0 ; delete seen[$3] };
/set_to_FALSE/ && seen[$3] { delete seen[$3] }' logfile.txt
这有可能使用更多的内存。将整个输入行存储在数组中比存储整数需要更多的 RAM。
注意 2:此脚本假定会话 ID 是唯一的。例如,如果不同的主机名(字段 2)可能生成相同的会话 ID,请尝试以下操作:
awk -F';' '/type=m/ { seen[$3$2]=1 };
/set_to_TRUE/ && seen[$3$2] { print $3 ; delete seen[$3$2] };
/set_to_FALSE/ && seen[$3$2] { delete seen[$3$2] }' logfile.txt
或者
awk -F';' '/type=m/ { seen[$3$2]=$0 };
/set_to_TRUE/ && seen[$3$2] {print seen[$3$2]"\n"$0;delete seen[$3$2]};
/set_to_FALSE/ && seen[$3$2] { delete seen[$3$2] }' logfile.txt