【问题标题】:how to grep by date time range?如何按日期时间范围grep?
【发布时间】:2011-07-28 20:48:50
【问题描述】:

我有一个日志文件看起来像:

2011-03-21 00:01 xxxx
2011-03-22 04:05 xxxx
....
2011-03-25 10:12 xxxx
....
2011-04-04 12:23 xxxx

我想要一个需要 2 个参数作为日期范围的脚本,例如:

grep-date-range.sh 2011-03-25 2011-04-02

它将在 [2011-03-25, 2011-04-02] 中找到所有日志。我知道对于特定情况我可以使用通配符,但在我看来它并不通用。谁能给我一个解决方案?

编辑: Python 脚本也是可以接受的。

【问题讨论】:

  • 您可以将一些超级复杂的 bash/cut/sed/awk 脚本链接在一起来做您想做的事情。但是,如果您知道 python 或 perl,那么编写一个小脚本来解析每行中的前三个数字并将其与参数中给出的范围进行比较可能会更容易。
  • 我真的很惊讶这作为一个 shell 脚本是多么困难。最大的障碍似乎是没有办法让日期接受自 1970 年以来的秒数输入。 WTF。

标签: python bash sed awk grep


【解决方案1】:

在这种情况下,编写一个简短的 Python 脚本可能会更好。该语言中的高级日期操作功能非常方便。

下面的脚本非常简单 - 只需多做一些工作,它就可以处理本地时差、夏令时等问题。

#! /usr/bin/python
import sys
from datetime import datetime
d_format = "%Y-%m-%d"

try:
    start = datetime.strptime(sys.argv[1], d_format)
    end = datetime.strptime(sys.argv[2], d_format) 
except (TypeError, IndexError):
    sys.stderr.write("Example: grep-date-range.py 2011-03-25 2011-04-02 \n")

for line in sys.stdin:
    try:
        date = datetime.strptime(line.split()[0], d_format)
        # suit the <=, <, comparisons bellow to your needs:
        if start <= date < end:
            sys.stdout.write(line)
    except (ValueError, IndexError):
        pass 

【讨论】:

  • datetime.strptime 在我的 python 中找不到。我可以使用 time.strptime。
  • 托德:你是从datetime import datetime做的吗? datetime 恰好是 datetime 模块内的工厂函数。如果您只是简单地导入日期时间,那么您必须使用 datetime.datetime.strptime - 这是非常标准的,并且肯定适用于您的 Python。
  • 抱歉 - 刚刚检查了文档,这是在 Python 2.5 中添加的(它已经有 6 或 7 年的历史了,如果你有任何软件比你更旧的系统,你应该考虑升级) .无论如何,旧 Python 版本的解决方法是:datetime.datetime(*(time.strptime(date_string, format)[0:6]))
【解决方案2】:

好吧,既然你的日期已经“可排序”了,

#!/bin/bash

a=2011-03-25
b=2011-06-02
a=${a//-/} # you can remove the dashes or not, up to you
b=${b//-/} # you can remove the dashes or not, up to you
awk -va=$a -vb=$b '{
    # save the first field if going to remove dash, 
    old=$1 
    # you can remove the dashes or not, up to you. Because your date is sortable
    # the dash will not matter.
    gsub(/-/,"",old) # for removing dash
    if( old >= a && old <=b ){ 
        # or use if ($1 >=a && $1 <=b ) (if not removing dash)
        print
    }
}' file

【讨论】:

  • 去掉破折号会增加很多不必要的复杂性:awk -v a=2011-03-25 -v b=2011-04-02 'a &lt;= $1 &amp;&amp; $1 &lt;= b'
  • @glenn,在他的情况下,没有必要,正如我也指出的那样。但是如果日期不是“可搜索的”,那么是的。
【解决方案3】:
sed -n "/$1/,/$2/p" $3

叫它:

fromTo "2011-03-25" "2011-04-02" foo.log

sed

  • -n:无输出
  • /from/,/to/: 匹配模式
  • p:打印

日期必须存在于文件中,如果您只有 2011-03-24 和 2011-03-26 作为日期,它将不起作用。它是字符串匹配,而不是日期匹配。 你不需要引用,但我碰巧有另一种日期格式,所以我有我的测试(“3 月 23 日”等等)。

【讨论】:

  • 只是一个小提示,如果日期没有排序,这将不起作用。
  • 是的,但是示例日志文件看起来已排序,因为大多数日志文件都避免了时间旅行。
  • 这就是为什么我说它只是一个小笔记:)
【解决方案4】:

好的,我终于明白了。基本思想是使用sort -m 合并给定的日期,使用sed 提取那些已知的行(感谢“用户未知”的建议)。如果数据文件尚未排序,请先对其进行排序。这里的假设是 YYYY-MM-DD 是一个常数,否则这是行不通的。

您可以通过使用mktemp 而不是/tmp/startstop 和比“START”和“END”更独特的字符串来使其更健壮。

/tmp/data 显然是你的数据文件。

#!/bin/bash

START=$1
END=$2

echo $START START > /tmp/startstop
echo $END END >> /tmp/startstop

sort -m /tmp/data /tmp/startstop | sed -n '/START/,/END/p'

【讨论】:

    猜你喜欢
    • 2013-05-24
    • 2012-11-10
    • 1970-01-01
    • 1970-01-01
    • 2023-01-10
    • 1970-01-01
    • 1970-01-01
    • 2017-04-23
    • 1970-01-01
    相关资源
    最近更新 更多