【问题标题】:Search for text between two time frame using sed使用 sed 在两个时间范围内搜索文本
【发布时间】:2014-05-16 22:53:39
【问题描述】:

我有带有时间戳的日志文件。我想使用sed 搜索两个时间戳之间的文本,即使第一个时间戳或最后一个时间戳不存在。 例如,如果我在 9:30 到 9:40 之间进行搜索,那么即使 9:30 和 9:40 都不存在但时间戳在 9:30 到 9:40 之间,它也应该返回文本。

我正在使用sed 一个班轮:

sed -n '/7:30:/,/7:35:/p' xyz.log  

但它仅在两个时间戳都存在时才返回数据;如果缺少其中一个时间戳,它将打印所有内容。如果时间是 12 小时格式,它将提取上午和下午的数据。

另外,我对不同的日志文件有不​​同的时间戳格式,所以我需要一个通用命令。

以下是一些时间格式示例:

<Jan 27, 2013 12:57:16 AM MST>

Jan 29, 2013 8:58:12 AM 

2013-01-31 06:44:04,883

其中一些包含 AM/PM,即 12 小时格式,而另一些包含 24 小时格式,所以我也必须考虑到这一点。

我也试过了,但是没用:

sed -n -e '/^2012-07-19 18:22:48/,/2012-07-23 22:39:52/p' history.log

【问题讨论】:

  • 请在 StackOverflow 上搜索您的答案。这个问题每周都会被询问和回答。祝你好运。
  • @shellter 如果经常被问到,也许您可​​以制作一个副本,以便我们可以正确关闭这个问题?

标签: unix sed grep


【解决方案1】:

由于您必须解析大量时间格式,sed 不是正确使用的工具。我会自动使用 Perl,但 Python 也会这样做,如果你愿意的话,你可能可以在 awk 中做到这一点。您需要标准化时间格式(您没有说任何关于日期的内容,所以我假设您只使用时间部分)。

#!/usr/bin/env perl
use strict;
use warnings;
use constant debug => 0;

my $lo = "09:30";
my $hi = "09:40";

my $lo_tm = to_minutes($lo);
my $hi_tm = to_minutes($hi);

while (<>)
{
    print "Read: $_" if debug;
    if (m/\D\d\d?:\d\d:\d\d/)
    {
        my $tm = normalize_hhmm($_);
        print "Normalized: $tm\n" if debug;
        print $_ if ($tm >= $lo_tm && $tm<= $hi_tm);
    }
}

sub to_minutes
{
    my($val) = @_;
    my($hh, $mm) = split /:/, $val;
    if ($hh < 0 || $hh > 24 || $mm < 0 || $mm >= 60 || ($hh == 24 && $mm != 0))
    {
        print STDERR "to_minutes(): garbage = $val\n";
        return undef;
    }
    return $hh * 60 + $mm;
}

sub normalize_hhmm
{
    my($line) = @_;
    my($hhmm, $ampm) = $line =~ m/\D(\d\d?:\d\d):\d\d\s*(AM|PM|am|pm)?/;
    my $tm = to_minutes($hhmm);
    if (defined $ampm)
    {
        if ($ampm =~ /(am|AM)/)
        {
            $tm -= 12 * 60 if ($tm >= 12 * 60);
        }
        else
        {
            $tm += 12 * 60 if ($tm < 12 * 60);
        }
    }
    return $tm;
}

我使用了样本数据:

<Jan 27, 2013 12:57:16 AM MST>

Jan 29, 2013 8:58:12 AM 

2013-01-31 06:44:04,883

Feb 2 00:00:00 AM
Feb 2 00:59:00 AM
Feb 2 01:00:00 AM
Feb 2 01:00:00 PM
Feb 2 11:00:00 AM
Feb 2 11:00:00 PM
Feb 2 11:59:00 AM
Feb 2 11:59:00 PM
Feb 2 12:00:00 AM
Feb 2 12:00:00 PM
Feb 2 12:59:00 AM
Feb 2 12:59:00 PM

Feb 2 00:00:00
Feb 2 00:59:00
Feb 2 01:00:00
Feb 2 11:59:59
Feb 2 12:00:00
Feb 2 12:59:59
Feb 2 13:00:00
Feb 2 09:31:00
Feb 2 09:35:23
Feb 2 09:36:23
Feb 2 09:37:23
Feb 2 09:35:00
Feb 2 09:40:00
Feb 2 09:40:59
Feb 2 09:41:00
Feb 2 23:00:00 
Feb 2 23:59:00
Feb 2 24:00:00
Feb 3 09:30:00
Feb 3 09:40:00

它产生了我认为正确的输出:

Feb 2 09:31:00
Feb 2 09:35:23
Feb 2 09:36:23
Feb 2 09:37:23
Feb 2 09:35:00
Feb 2 09:40:00
Feb 2 09:40:59
Feb 3 09:30:00
Feb 3 09:40:00

我确定这不是进行处理的唯一方法;不过,它似乎有效。


如果您需要进行日期分析,则需要使用CPAN 中的日期或时间操作包之一来处理问题。上面的代码还硬编码了脚本中的时间。您可能希望将它们作为命令行参数处理,这是完全可行的,但上面没有编写脚本。

【讨论】:

  • 我必须考虑在运行命令的机器上是否安装了 perl,因为我将在不同服务器上的不同风格的 unix 上运行它。如果 sed 不是答案... AWK 解决方案也可以。
  • 然后将 Perl 转换为 awk。这可能是可行的,甚至可以编写函数(awk 允许您编写函数)。但是有一些问题需要处理,比如使用函数来替换正则表达式,我不愿意花时间去处理这些问题,因为 Perl 可以在我可能感兴趣的任何机器上使用(这意味着我对 Windows 不感兴趣 — YMMV;Perl 可用于 Windows,但规定安装它可能对您的客户来说是不可接受的)。您需要知道的主要技巧是 \d -> [0-9]\D -> [^0-9]
猜你喜欢
  • 1970-01-01
  • 2017-06-12
  • 2019-08-12
  • 2011-09-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-27
  • 2011-07-17
相关资源
最近更新 更多