gawk - 抑制匹配线的输出

时间:2016-01-22 23:27:42

标签: bash awk sed gawk

我遇到了gawk打印不需要的输出的问题。我想在文件中找到与表达式匹配的行,测试以查看行中的信息是否与某个条件匹配,然后打印该行(如果有)。我得到了我想要的输出,但是gawk也打印了与表达式匹配的每一行,而不仅仅是符合条件的行。

我正在尝试搜索包含要执行的某些操作的日期和时间的文件。我想只显示未来包含时间的行。日期的格式如下:

text... 2016-01-22 10:03:41 more text...

我尝试使用sed打印所有以当前小时开头的行,但不保证文件包含该小时的行,(并且不能保证所有行都行有任何特定的年,月,日等)所以我需要更强大的东西。我决定尝试将时间转换为自纪元以来的秒数,并将其与当前systime进行比较。如果转换产生的数字大于systime,我想打印该行。

现在似乎gawk的{​​{1}}功能是关键。不幸的是,它需要以下列格式输入:

mktime()

我目前正在搜索测试文件(名为yyyy mm dd hh mm ss ),寻找与日期格式匹配的正则表达式。

编辑:测试文件只包含每行的日期和时间,没有其他文本。

我使用timecomp用空格替换日期分隔符(即/, - 和:),然后使用以下语句将输出传送到名为sed的gawk脚本:

stime

这是脚本

sed -e 's/[-://_]/ /g' timecomp | gawk -f stime

现在这是获取我想要的基本信息,但它也打印出与原始表达式匹配的所有内容,而不仅仅是包含未来时间的行。样本输出:

# stime
BEGIN { tsec=systime();  } /.*20[1-9][0-9] [0-1][1-9] [0-3][0-9] [0-2][0-9][0-6][0-9] [0-6][0-9]/ { 
    if (tsec < mktime($0))
        print "\t" $0    # the tab is just to differentiate the desired output from the other lines that are being printed.
} $1

如何在将来只打印线条?

注意:我在Mac上这样做,但是我希望它可以移植到Linux上,因为我最终要为工作中的一些任务做这件事。

我想尝试在一个脚本中完成此操作,而不是要求2016 01 22 13 23 20 2016 01 22 14 56 57 2016 01 22 15 46 46 2016 01 22 16 32 30 2016 01 22 18 56 23 2016 01 22 18 56 23 2016 01 22 22 22 28 2016 01 22 22 22 28 2016 01 22 23 41 06 2016 01 22 23 41 06 2016 01 22 20 32 33 语句重新格式化日期,但我遇到了其他可能需要不同问题的问题,所以我坚持现在这个。

任何帮助将不胜感激!谢谢!

已回答:我的脚本的最后一行有一个sed,这是额外输出的原因。

2 个答案:

答案 0 :(得分:1)

而不是awk,这是一个(几乎)纯粹的Bash解决方案:

#!/bin/bash

# Regex for time string
re='[0-9]{4}-[0-9]{2}-[0-9]{2} ([0-9]{2}:){2}[0-9]{2}'

# Current time, in seconds since epoch
now=$(date +%s)

while IFS= read -r line; do

    # Match time string
    [[ $line =~ $re ]]
    time_string="${BASH_REMATCH[0]}"

    # Convert time string to seconds since epoch
    time_secs=$(date -d "$time_string" +%s)

    # If time is in the future, print line
    if (( time_secs > now )); then
        echo "$line"
    fi

done < <(grep 'pattern' "$1")

利用Coreutils date格式将日期转换为自纪元以来的秒数,以便轻松比较两个日期:

$ date
Fri, Jan 22, 2016 11:23:59 PM
$ date +%s
1453523046

-d参数取字符串作为输入:

$ date -d '2016-01-22 10:03:41' +%s
1453475021

该脚本执行以下操作:

  • 使用grep过滤输入文件(对于包含通用pattern的行,但可以是任何内容)
  • 循环包含pattern
  • 的行
  • 将该行与匹配日期/时间字符串yyyy-mm-dd hh:mm:ss的正则表达式匹配并提取匹配项
  • 将时间字符串转换为自纪元以来的秒数
  • 将该值与$now中的时间进行比较,这是自纪元以来的当前日期/时间(以秒为单位)
  • 如果以后是日志文件的时间,请打印

对于像这样的示例输入文件

text 2016-01-22 10:03:41 with time in the past
more text 2016-01-22 10:03:41 matching pattern but in the past
other text 2017-01-22 10:03:41 in the future matching pattern
some text 2017-01-23 10:03:41 in the future but not matching
blahblah 2022-02-22 22:22:22 pattern and also in the future

结果是

$ date
Fri, Jan 22, 2016 11:36:54 PM
$ ./future_time logfile
other text 2017-01-22 10:03:41 in the future matching pattern
blahblah 2022-02-22 22:22:22 pattern and also in the future

答案 1 :(得分:1)

这就是我现在的工作。它适用于几种不同的日期格式以及不仅仅具有日期和时间的实际文件。它适用的默认格式是yyyy / mm / dd,但如果需要,它需要一个参数来指定mm / dd / yyyy格式。

BEGIN { tsec=systime(); dtstr=""; dt[1]="" } /.*[0-9][0-9]:[0-9][0-9]:[0-9][0-9]/ { 
cur=$0

if ( fm=="mdy" ) {
    match($0,/[0-1][1-9][-_\/][0-3][0-9][-_\/]20[1-9][0-9]/)        # mm dd yyyy
    section=substr($0,RSTART,RLENGTH)
    split(section, dt, "[-_//]")
    dtstr=dt[3] " " dt[1] " " dt[2]
    gsub(/[0-1][1-9][-\/][0-3][0-9][-\/]20[1-9][0-9]/, dtstr, cur)
}

gsub(/[-_:/,]/, " ", cur)
match(cur,/20[1-9][0-9] [0-1][1-9] [0-3][0-9][[:space:] ]*[0-2][0-9] [0-6][0-9] [0-6][0-9]/)
arr=mktime(substr(cur,RSTART,RLENGTH))

if ( tsec < arr)
    print $0
}

当我找到更多格式时,我会添加更多格式选项,但这适用于我迄今为止测试的所有不同文件。如果它们具有mm / dd / yyyy格式,您可以使用:

调用它
gawk -f stime fm=mdy filename

我计划添加一个选项来指定您想要查看的时间窗口,但这是一个很好的开始。再次感谢大家,这将大大简化工作中的一些任务(我基本上必须检索大量数据,通常在时间压力下取决于具体情况)。