在两个方向有条件地浏览文件

时间:2015-04-30 11:38:04

标签: regex grep

我有一个cgi脚本的几个实例写的日志文件。我需要提取某些信息,具有以下典型工作流程:

  1. 搜索第一次出现RequestString
  2. 从该日志行中提取PID
  3. 向后搜索PID<separator>ConnectionString的第一个匹配项,以识别发起请求的客户端
  4. 使用ConnectionString执行某些操作,然后在'RequestString'
  5. 之后重复搜索

    最好的方法是什么?我正在考虑编写一个perl脚本来缓存最后N行,然后匹配这些行来执行3.

    有没有更好的方法呢?像扩展的正则表达式那样可以做到这一点吗?

    带有行号的样本供参考 - 不属于文件的一部分:

    1 date    pid1    ConnectionString1
    2 date    pid2    ConnectionString2
    3 date    pid3    ConnectionString3
    4 date    pid2    SomeOutput2
    5 date    pid2    SomeOutput2
    6 date    pid4    ConnectionString4
    7 date    pid3    SomeOutput3
    8 date    pid4    RequestString4
    9 date    pid1    SomeOutput1
    10 date    pid1    ConnectionString1
    11 date    pid1    RequestString1
    12 date    pid5    RequestString5
    

    当我浏览此示例文件时,我希望以下内容匹配:

    • 第8行,与第6行配对
    • 第11行,与第10行(而不是第1行)配对

    具体而言,不应匹配以下内容:

    • 第12行,因为找不到与该pid匹配的ConnectionString(pid5)
    • 第1行,因为在该pid的下一个RequestString之前,该pid有一个新的ConnectionString(第10行)。想象一下,在记录RequestString之前第一次连接尝试失败了)
    • 来自pid2 / pid3的任何行,因为他们没有记录RequestString。

    我可以想象用正版选项编写正则表达式。匹配\ n:((pid\d)\s*(ConnectionString\d))(?!\1).*\2\s*RequestString\d,然后使用\3来识别客户端。

    然而,ConnectionString的{​​{1}}比RequestString更多(可能在1000到10000倍之间),所以我的直觉是首先选择RequestString然后回溯。

    我想我可以使用(?&lt;)进行后视,但ConnectionStringRequestString之间的长度基本上是任意的 - 这样会有效吗?

1 个答案:

答案 0 :(得分:1)

这些方面的东西:

#!/bin/bash
# Find and number all RequestStrings, then loop through them
grep -n RequestString file | while IFS=":" read n string; do
   echo $n,$string    # Debug
   head -n $n file | tail -r | grep -m1 Connection
done

<强>输出

4,RequestString 1
6189:Connection
7,RequestString 2
7230:Connection
9,RequestString 3
8280:Connection

使用此输入文件

6189:Connection

RequestString 1
7229:Connection
7230:Connection
RequestString 2
8280:Connection
RequestString 3

注意:我使用了tail -r,因为OSX缺少tac,我更喜欢这样做。