尝试使用grep匹配同一行上的多个模式

时间:2017-07-19 09:29:44

标签: linux bash awk sed grep

我非常难过。我正在搜索多个文件,看起来像这样(通过find - 所需的开始日期)和管道到grep,所以我可以用这个命令提取一组行:

find logdir/ -type f -regextype sed -regex ".*2016-06-22.*" | while read fname
do
  zgrep -a -P -B9 ".*COOKTHE.*slave.*" $fname
done

所以我可以输出这些行:

2017-05-10 12:14:54 DEBUG[dispatcher-1533] something.else.was.here.Pia - http://server:9999/cookout/123123123123/entry c7aab5a3-0dab-4ce1-b188-b5370007c53c request:
 HEADERS:
 Host: server:9999
 Accept: */*
 User-Agent: snakey-requests/2.12.3
 Accept-Encoding: gzip, deflate
 Connection: keep-alive
 Timeout-Access: <function1>
 CONTENT:
  {"operation": "COOKTHE", "reason": "sucker verified", "username": "slave"}

我尝试从第一行匹配中提取整个字符串日期模式(2017-05-10 12:14:54)数字模式123123123123,并从最后一行中提取整行匹配。 ({"operation": "COOKTHE", "reason": "sucker verified", "username": "slave"}

如何用grep,sed或awk提取这些?

3 个答案:

答案 0 :(得分:1)

首先,让我们简化您的初始查询。我认为你不需要正则表达式; globbing更简单,更快速,更清晰。同样,您不需要grep的-P选项,因为您没有使用PCRE。这也减缓了事情的发展。

find logdir/ -type f -name '*2016-06-22*' | while read fname
do
  zgrep -a -B9 '"COOKTHE".*"slave"' "$fname"
done | grep -e ^20 -e '{'

重新创建原始逻辑,但运行速度要快一些。它还添加了一个过滤器,仅显示您要求的两条线。但是,我担心-B9不是一个好的解决方案,因为可能会有可变数量的标题要跟踪。最后的过滤器也有点简陋,只是为了快速。

这是一个更完整的解决方案:

find logdir/ -type f -name '*2016-06-22*' | while read fname
do
  zcat "$fname" | awk '
    /^20/ && $6 ~ /^http/ {
      split($6, url, "/")           # split the URL by slashes
      stamp = $1 " " $2 " " url[5]  # "2017-05-10 12:14:54 123123123123"
    }
    /{.*"COOKTHE".*"slave"/ { print stamp; print }
  '
done

这会在stamp变量中保存URL的日期,时间和第5个片段,并且只有在JSON行中匹配时才打印它。我修改了你的正则表达式,包括一个{来表示JSON的开头以及引号以改善你的匹配,但是你可以把它改成你喜欢的任何东西。此正则表达式不需要前导.*

AWK连接相邻的项目,因此$1 " " $2 " " url[5]仅表示第一列的值,空格,第二列,另一个空格,然后是URL的第5项(注意“http:”后面的空项)。

这不会告诉您匹配文本来自哪个文件(与grep -H比较)。要做到这一点,你想要:

  zcat "$fname" | awk -v fname="$fname:" '
    # … (see above)
    /{.*"COOKTHE".*"slave"/ { print fname stamp; print fname $0 }
  '

如果你正在寻找的JSON字符串始终被放置和间隔,你可以改为使用最终条款$2 ~ /"COOKTHE"/ && $NF ~ /"slave"/来提高awk的速度(实际上,它能够更快地失败)。

答案 1 :(得分:0)

您当前输入的

awk 解决方案:

awk 'NR==1{ sub(/http:\/\/[^\/]+\/[^\/]+\//,"",$6); 
     print $1,$2,substr($6,1,index($6,"/")-1)}END{ print $0 }' input

输出:

2017-05-10 12:14:54 123123123123
  {"operation": "COOKTHE", "reason": "sucker verified", "username": "slave"}

答案 2 :(得分:0)

… | while read fname
do
  zcat "$fname" | tr '\n' '\f' |
    grep -o -P '\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d.*?COOKTHE[^}]*\}' |
      tr '\f' '\n'
done

如果您的输入已包含formfeed-characters(\f),则可以使用不应出现在输入中的任何其他字符。