如何使用 awk 记录这 5 分钟,然后将输出转换为另一个文件

如何使用 awk 记录这 5 分钟,然后将输出转换为另一个文件

我有一个日志文件,名称为listlog,内容为:

2021-08-12 16:09:17 textsp sdgg
reponse:success
prams:invalid
line 3
2021-08-12 16:10:17 textdfdfdlfs sfdfs
reponse: failed
prams:valid
line 3

我想过滤 t1 和 t2 之间记录的日志并打印连续 2 行的日志行。我使用 awk 和 if 条件和 grep 编写。但我得到了错误:

这是我想要过滤并写入新文件的内容,假设 t1 < (16:09:17, 16:19:17) < t2 :

2021-08-12 16:09:17 textsp sdgg
reponse:success
prams:invalid
2021-08-12 16:10:17 textdfdfdlfs sfdfs
reponse: failed
prams:valid

这是我写的 awk 脚本:

t1=$(date -d "$min_change minutes ago" +"%F %T")
t2=$(date +"%F %T")
cat $listlog | awk -v t1="$t1" -v t2="$t2" -v listlog="$listlog" '{
        if (match($0 ~ /^[0-9]{4}(-[0-9]{2}){2}))
        {
                if ( $0 > t1 && $0 < t2 | $0 ~ t2 )
                {
                        grep -A 2 $0 $listlog >> /tmp/temp.txt
                }
        }
        }'

这是我得到的错误:

awk: cmd. line:2:       if (match($0 ~ /^[0-9]{4}(-[0-9]{2}){2}))
awk: cmd. line:2:                       ^ unterminated regexp
awk: cmd. line:3:       if (match($0 ~ /^[0-9]{4}(-[0-9]{2}){2}))
awk: cmd. line:3:                                                ^ unexpected newline or end of string
awk: cmd. line:4:               if ( $0 > t1 && $0 < t2 | $0 ~ t2 )
awk: cmd. line:4:                                         ^ syntax error.
awk: cmd. line:5:               if ( $0 > t1 && $0 < t2 | $0 ~ t2 ) 
awk: cmd. line:5:                                                   ^ unexpected newline or end of string
awk: cmd. line:6:                       grep -A 2 $0 $listlog >> /temp/temp.txt
awk: cmd. line:6:                                             ^ syntax error
awk: cmd. line:7:                       grep -A 2 $0 $listlog >> /temp/temp.txt.
awk: cmd. line:7:                                                                ^ unexpected newline or end of string

答案1

甚至很难开始描述脚本的问题所在,但这里总结了最重要的几点:

  1. 你写的不是awk剧本。它甚至不是awk嵌入 shell 脚本中的脚本(通常完全没问题)。这是一些 shell 代码的奇怪混合,并尝试在awk其中包含 shell 代码(awk不解释或运行 shell 命令)。

    无论如何,你不能grep在内部像这样运行awk,除非将其分叉为外部进程。并且不需要这样做,因为awk可以进行正则表达式模式匹配。

  2. 您的任何代码中都没有缩进,这使得阅读起来非常困难。

    更新:我刚刚编辑了你的问题以重新格式化它,结果发现你的代码中确实有一些缩进。但是您使用 HTML 标签对其进行格式化,<br/>而不是使用 Markdown 编辑器的内置文本格式化功能。

  3. 第 1 点和第 2 点可能是您发布问题后 7 小时内没有得到答案甚至评论的原因。任何读者(至少是我的)的最初反应都是“WTF?这毫无意义。我什至不知道从哪里开始......通过”。

  4. 您无法在 shell 中或awk尝试执行日期比较的方式进行日期比较。要进行大于或小于等数字比较,您需要将日期转换为数字(即unixtime_t格式,自“纪元”以来的秒数,即UTC 1970年1月1日午夜)。

  5. 可以在 中执行您想要的操作awk,但会比必要的更困难,因为awk没有任何内置的日期转换函数。在 中会容易得多perl,它确实有很好的日期和时间库函数。这对您来说是一件好事,因为您编写的脚本perl在风格上比代码更接近于代码awk


这是一种相当简单、直接的方法,可以在 Perl 中完成您想要的操作。它需要命令行参数(使用 perl 的获取选择::标准库模块)。 Getopt::Std是一个核心 Perl 库模块,包含在 Perl 中。

参数可以按任何顺序提供。所有选项参数( 、 和 )都不-m-n强制性-s的,如果命令行上未提供,它们都有默认值。任何未处理的参数Getopt::Std都被视为输入文件名。该脚本可以处理标准输入以及任何输入文件名,因此您可以将日志文件通过管道传输到其中。

该脚本还使用日期::解析来自 perl 的模块时间::日期将日期字符串转换为自纪元以来的秒数的集合。

Date::Parseperl 不包含它,需要安装。如果您使用 Debian(或 Ubuntu 或 Mint 或其他 Debian 相关发行版),您可以使用sudo apt-get install libtimedate-perl.大多数其他发行版也会将其打包。 Centos 包是perl-TimeDate-2.30-2对于 Centos 7,或perl-TimeDate-2.30-15对于 Centos 8。否则,您可以使用cpan.

#!/usr/bin/perl
use strict;
use Getopt::Std;
use Date::Parse;

my %opts;
getopt('m:s:n:', \%opts); # -m minutes, -s start time, -n number of lines

my $st  = $opts{s} || -1; # start time, default now.
my $min = $opts{m} ||  5; # number of minutes after $st to match, default 5.
my $nl  = $opts{n} ||  2; # No. of extra lines to print after match, default 2.

if ($st == -1) {
  $st = time();           # now
} else {
  $st = str2time($st);    # convert time string to seconds since epoch
};
my $et = $st + $min * 60; # calculate ending time

my $p = -1; # input lines are printed only when $p > -1

# main loop, read and process all input file(s).
while (<>) {
  if (m/^(\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d)/) {
    my $t = str2time($1);
    $p = $nl if ($t >= $st && $t <= $et);
  };

  if ($p > -1) { print; $p-- };
};

将其另存为,例如extract.pl,使其可执行chmod +x extract.pl并像这样运行它:

$ ./extract.pl -s "2021-08-12 16:09:00" -n 2 -m 5 listlog 
2021-08-12 16:09:17 textsp sdgg
reponse:success
prams:invalid
2021-08-12 16:10:17 textdfdfdlfs sfdfs
reponse: failed
prams:valid

如果需要,您可以重定向输出,例如通过附加>>/tmp/temp.txt到命令行末尾。

相关内容