如何使用大文本文件中的grep / sed从日期范围中获取文本?


9

我有大文件文本(将近3GB)-它是一个日志文件。我想从该文件中获取与7月13日至7月19日的日期范围相对应的文本行。我的日志格式为:

2016-07-12 < ?xml version>
2016-07-13 < ?xml version>
2016-07-18 < ?xml version>
2016-07-18 < ?xml version>
2016-07-19 < ?xml version>
2016-07-20 < ?xml version>
sample text sample text
sample text sample text
sample text sample text
2016-07-20 < ?xml version>
sample text sample text
2016-07-20 < ?xml version>

所以在grep/ sed之后应该这样输出:

2016-07-13 < ?xml version>
2016-07-18 < ?xml version>
2016-07-18 < ?xml version>
2016-07-19 < ?xml version>

我怎么能得到这个?


2
你确定你是六月吗?样本日志文件中的所有日期均为7月,而所需的输出样本表示您的意思是后者。
David Foerster

Answers:


13

有了grep,如果你知道行数你愿意,你可以使用上下文选项-A模式后打印线

grep -A 3 2016-07-13 file

这将为您提供2013-07-13和接下来的3行

sed您可以使用日期划定这样

sed -n '/2016-07-13/,/2016-07-19/p' file

它将打印从第一行(2016-07-13)到第一行(包括2016-07-19)的所有行。但这假设您在2016-07-19中只有一行(它将不会打印下一行)。如果有多行,请改用下一个日期,并d从中删除输出

sed -n '/2016-07-13/,/2016-07-20/{/2016-07-20/d; p}' file


4

awk 解:

$ awk '/^2016-07-13.*/,/2016-07-19.*/'  input.txt                                   
2016-07-13 < ?xml version> 
2016-07-18 < ?xml version> 
2016-07-18 < ?xml version> 
2016-07-19 < ?xml version> 

基本上打印从以开头的行2016-07-13到以开头的行2016-07-19


4

所有其他当前答案取决于以下事实:日志文件条目按时间顺序排序;或者日期范围可以轻松地与正则表达式匹配。如果您想要一个更通用的解决方案,我们需要做更多的编程。

我展示了这个GNU AWK脚本:

#!/usr/bin/gawk -f
BEGIN {
    starttime = mktime(starttime)
    endtime = mktime(endtime)
}

func in_range(n, start, end) {
    return start <= n && n < end
}

match($0, /^([0-9]{4})-([0-9]{2})-([0-9]{2})\s/, m) &&
    in_range(mktime(m[1] " " m[2] " " m[3] " 00 00 00"), starttime, endtime)

您可以通过变量提供开始和结束时间starttime,并endtime在格式mktime理解(YYYY MM DD hh dd ss)。因此awk,假设上面的Awk脚本filter-log-dates.awk位于当前工作目录中的可执行文件中,并且日志文件为mylog.txt

./filter-log-dates.awk -v starttime='2016 07 13 00 00 00' -v endtime='2016 07 20 00 00 00' mylog.txt

请注意,结束时间是互斥的,即有效的日志记录必须在结束时间之前有一个时间戳记。

如果您的时间戳格式不同,则可以调整传递给该match函数的正则表达式以适合它。


3

您可以分步进行。查找与您的起始模式匹配的第一行的编号。查找与您的结束模式匹配的最后一行的编号。然后在这两行之间提取测试。这可以如下进行。

grep -n 2016-07-13 bigtextfile | head -1
grep -n 2016-07-19 bigtestfile | tail -1
# Say the first number is 1234 and the second 5678, then use...
awk 'NR>=1234 && NR<=5678' bigtestfile > rangeoftext

可以在一个awk命令中完成所有操作,但是这些步骤可以使执行起来更容易。在awk中,NR变量是当前行号,并且由于在模式(NR> = 1234 && NR <= 5678)之后未指定任何操作,因此默认操作是打印该范围内的行。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.