【问题标题】:GREP for a dynamic pattern in a file and print the other lines having former pattern and another patternGREP 用于文件中的动态模式并打印具有前一个模式和另一个模式的其他行
【发布时间】:2015-07-21 06:05:59
【问题描述】:

假设我有一个如下所示的日志文件:

06/30/2015 00:17:20.716  INFO   06z07mjBYxFpzs Matched Line
06/30/2015 00:17:20.723  INFO   06z07mjBYxFpzs Some Data xxyyzz
06/30/2015 00:17:20.735  INFO   06z07mdgC66vHc Matched Line
06/30/2015 00:17:20.759  INFO   06z07mGDQ9thtY Some Data xxyyzz
06/30/2015 00:17:20.755  INFO   06z07mdgC66vHc Matched Line
06/30/2015 00:17:20.784  INFO   06z07mdgC66vHc Some Data xxyyzz
06/30/2015 00:17:20.827  INFO   06z07n2q9S4g07 Some Data xxyyzz
06/30/2015 00:17:20.855  INFO   06z07mxt44CF03 Some Data xxyyzz
06/30/2015 00:17:20.861  INFO   06z07n5mxfYkHg Some Data xxyyzz
06/30/2015 00:17:20.873  INFO   06z07nm473brzB Some Data xxyyzz
06/30/2015 00:17:20.902  INFO   06z07mM059k0tZ Some Data xxyyzz
06/30/2015 00:17:20.970  INFO   06z07nx2lv9wzC Matched Line
06/30/2015 00:17:20.974  INFO   06z07nx2lv9wzC Some Data xxyyzz
06/30/2015 00:17:20.991  INFO   06z07ngwMW16zz Matched Line
06/30/2015 00:17:20.994  INFO   06z07ngwMW16zz Some Data xxyyzz
06/30/2015 00:17:21.085  INFO   06z07n42C6Qczx Some Data xxyyzz
06/30/2015 00:17:21.094  INFO   06z07nMgPJpPv1 Matched Line
06/30/2015 00:17:21.094  INFO   06z07mxR42tZzw Some Data xxyyzz
06/30/2015 00:17:21.094  INFO   06z07mWbfVCGD3 Some Data xxyyzz
06/30/2015 00:17:21.095  INFO   06z07nMgPJpPv1 Matched Line
06/30/2015 00:17:21.100  INFO   06z07nMgPJpPv1 Some Data xxyyzz
06/30/2015 00:17:21.123  INFO   06z07p0yBwLv0b Some Data xxyyzz
06/30/2015 00:17:21.132  INFO   06z07nSLzf66Hk Matched Line
06/30/2015 00:17:21.137  INFO   06z07nSLzf66Hk Some Data xxyyzz

我想做的是:

  • 任何一行都包含"Matched Line",我需要获取第4列中的唯一ID(例如06z07mjBYxFpzs),并且,
  • 搜索具有该唯一 ID + 文本 "Some Data xxyyzz" 的其他行,并且,
  • 在控制台上打印具有 (unique id + "Some Data xxyyzz") 匹配模式的行作为最终输出。

所以在这种情况下,输出应该是:

06/30/2015 00:17:20.723  INFO   06z07mjBYxFpzs Some Data xxyyzz
06/30/2015 00:17:20.784  INFO   06z07mdgC66vHc Some Data xxyyzz
06/30/2015 00:17:20.974  INFO   06z07nx2lv9wzC Some Data xxyyzz
06/30/2015 00:17:20.994  INFO   06z07ngwMW16zz Some Data xxyyzz
06/30/2015 00:17:21.100  INFO   06z07nMgPJpPv1 Some Data xxyyzz
06/30/2015 00:17:21.137  INFO   06z07nSLzf66Hk Some Data xxyyzz

我在这里谈论的文件是一个巨大的文件(约 200 GB 文件;有数百万条记录),位于共享服务器上,所以我无法运行需要大量时间的脚本或命令时间。

[编辑] - 目前通过 fgrep 通过在一个文件中打印来自 Matched Line 的唯一 ID 和在另一个文件中打印 Some Data xxyyzz 的唯一 ID;但寻找单行grepawksed 命令(无需创建多个文件到fgrep

[EDIT 2] - 此输出不在文件中,而是一系列grepsort 的中间输出。

[EDIT 3] - 更新了示例输入(不是按顺序排列,而是混乱):

06/30/2015 00:17:21.094  INFO   06z07nMgPJpPv1 Matched Line
06/30/2015 00:17:20.716  INFO   06z07mjBYxFpzs Matched Line
06/30/2015 00:17:20.735  INFO   06z07mdgC66vHc Matched Line
06/30/2015 00:17:20.759  INFO   06z07mGDQ9thtY Some Data xxyyzz
06/30/2015 00:17:20.755  INFO   06z07mdgC66vHc Matched Line
06/30/2015 00:17:20.784  INFO   06z07mdgC66vHc Some Data xxyyzz
06/30/2015 00:17:20.827  INFO   06z07n2q9S4g07 Some Data xxyyzz
06/30/2015 00:17:20.855  INFO   06z07mxt44CF03 Some Data xxyyzz
06/30/2015 00:17:20.861  INFO   06z07n5mxfYkHg Some Data xxyyzz
06/30/2015 00:17:20.873  INFO   06z07nm473brzB Some Data xxyyzz
06/30/2015 00:17:20.723  INFO   06z07mjBYxFpzs Some Data xxyyzz
06/30/2015 00:17:20.902  INFO   06z07mM059k0tZ Some Data xxyyzz
06/30/2015 00:17:20.970  INFO   06z07nx2lv9wzC Matched Line
06/30/2015 00:17:20.974  INFO   06z07nx2lv9wzC Some Data xxyyzz
06/30/2015 00:17:20.991  INFO   06z07ngwMW16zz Matched Line
06/30/2015 00:17:21.085  INFO   06z07n42C6Qczx Some Data xxyyzz
06/30/2015 00:17:21.094  INFO   06z07nMgPJpPv1 Matched Line
06/30/2015 00:17:21.094  INFO   06z07mxR42tZzw Some Data xxyyzz
06/30/2015 00:17:20.994  INFO   06z07ngwMW16zz Some Data xxyyzz
06/30/2015 00:17:21.094  INFO   06z07mWbfVCGD3 Some Data xxyyzz
06/30/2015 00:17:21.095  INFO   06z07nMgPJpPv1 Matched Line
06/30/2015 00:17:21.100  INFO   06z07nMgPJpPv1 Some Data xxyyzz
06/30/2015 00:17:21.123  INFO   06z07p0yBwLv0b Some Data xxyyzz
06/30/2015 00:17:21.132  INFO   06z07nSLzf66Hk Matched Line
06/30/2015 00:17:21.137  INFO   06z07nSLzf66Hk Some Data xxyyzz

【问题讨论】:

    标签: regex awk sed grep text-extraction


    【解决方案1】:

    有序数据

    以下内容只遍历文件一次,因此应该很快:

    $ awk '/Matched Line/{id=$4;next;} id==$4' file.log
    06/30/2015 00:17:20.723 INFO 06z07mjBYxFpzs Some Data xxyyzz
    06/30/2015 00:17:20.784 INFO 06z07mdgC66vHc Some Data xxyyzz
    06/30/2015 00:17:20.974 INFO 06z07nx2lv9wzC Some Data xxyyzz
    06/30/2015 00:17:20.994 INFO 06z07ngwMW16zz Some Data xxyyzz
    06/30/2015 00:17:21.100 INFO 06z07nMgPJpPv1 Some Data xxyyzz
    06/30/2015 00:17:21.137 INFO 06z07nSLzf66Hk Some Data xxyyzz
    

    在示例输入(原始问题)中,所有Some Data 行都紧跟在它们的Matched Line 后面。这使得这个快速而简单的解决方案成为可能。

    如何在管道中使用

    awk 在管道中运行良好。如果输入不是来自文件,而是来自管道,如 Edit 2,则使用以下内容:

    cmd1 <file.log | cmd2 | awk '/Matched Line/{id=$4;next;} id==$4' | cmd3
    

    工作原理

    • /Matched Line/{id=$4;next;}

      每当我们找到包含文本Matched Line 的行时,我们将其ID 保存在变量id 中。由于我们不想打印 Matched Line,我们告诉 awk 跳过其余的命令并跳转到 next 行。

    • id==$4

      只要当前行的 ID(字段 4)与我们保存的 id 匹配,我们就会打印该行。

      (在 awk 术语中,id==$4 是一个条件:它评估为真或假。当条件为真时,执行操作。在这种情况下,我们不指定任何操作,因此 awk 执行默认操作,即打印该行。)

    部分有序数据

    Edit 3中,数据行可以出现在匹配行之后的某个随机位置。在这种情况下:

    $ awk '/Matched Line/{id[$4]=1;next;} id[$4]' file.log
    06/30/2015 00:17:20.784 INFO 06z07mdgC66vHc Some Data xxyyzz
    06/30/2015 00:17:20.723 INFO 06z07mjBYxFpzs Some Data xxyyzz
    06/30/2015 00:17:20.974 INFO 06z07nx2lv9wzC Some Data xxyyzz
    06/30/2015 00:17:20.994 INFO 06z07ngwMW16zz Some Data xxyyzz
    06/30/2015 00:17:21.100 INFO 06z07nMgPJpPv1 Some Data xxyyzz
    06/30/2015 00:17:21.137 INFO 06z07nSLzf66Hk Some Data xxyyzz 
    

    或者,在管道中:

    cmd1 file.log | awk '/Matched Line/{id[$4]=1;next;} id[$4]'
    

    【讨论】:

    • 很好的答案。也许这个awk '($5" "$6 == "Matched Line"){ id=$4; next } id == $4' logfile 可以给你更快的速度,这真的取决于原始输入。
    • @John1024 - 感谢您的简单命令。如果“匹配行”和“某些数据”行没有按特定顺序排列怎么办。请参阅有问题的更新输入。但是,您的回答很有用,鼓励我学习 awk!
    • @BadwolF 从编辑 3 中,我看到数据行永远不会出现在它们相应的匹配行之前。这意味着快速的单通道方法可以工作。我为此添加了一个解决方案。
    • @John1024 - 太棒了......谢谢!出于好奇,如果数据行确实在匹配行之前或以任何随机顺序排列,该怎么办。
    • @BadwolF 非常好。因为你的文件太大了,如果数据行可以在匹配行之前大量出现,那么我们需要读取文件两次,一次获取 ID,一次选择数据行。当然,这会减慢它的速度,并且会使其难以在管道中使用。
    【解决方案2】:
    grep "Matched Line" data.txt  | awk '{print $4}' | xargs -l1 -i grep {} data.txt | grep -v "Matched Line"
    
    1. 搜索所有“匹配行”
    2. 将行中的第 4 个元素打印到标准输出
    3. 对于输出中的每一行,运行 grep:搜索打印的 id
    4. 然后再次搜索,但没有“匹配行”

    输出:

    06/30/2015 00:17:20.723 INFO 06z07mjBYxFpzs Some Data xxyyzz
    06/30/2015 00:17:20.784 INFO 06z07mdgC66vHc Some Data xxyyzz
    06/30/2015 00:17:20.784 INFO 06z07mdgC66vHc Some Data xxyyzz
    06/30/2015 00:17:20.974 INFO 06z07nx2lv9wzC Some Data xxyyzz
    06/30/2015 00:17:20.994 INFO 06z07ngwMW16zz Some Data xxyyzz
    06/30/2015 00:17:21.100 INFO 06z07nMgPJpPv1 Some Data xxyyzz
    06/30/2015 00:17:21.100 INFO 06z07nMgPJpPv1 Some Data xxyyzz
    06/30/2015 00:17:21.137 INFO 06z07nSLzf66Hk Some Data xxyyzz 
    

    或者,使用 bash 的进程替换,我们可以将文件 data.txt 的读取次数减少到只有两次:

    grep -f <(grep "Matched Line" data.txt  | awk '{print $4}') data.txt | grep -v "Matched Line"
    

    【讨论】:

    • 如果我正确理解了该命令,那么它将获取数组中的所有唯一 ID,并在整个文件中循环遍历该数组(如果数组有 n 个值,则为 n 次)以消除“匹配”的行数组中每个值的“线”模式。如果是,那么我们已经这样做了,并且该进程运行了几个小时并且有点挂起服务器。
    • @Richard 我在您的答案代码中添加了使用 grep 的方法,就像您的方法一样,但避免使用 xargs 以便必须读取文件的次数减少到只有两次。它还具有消除输出中重复行的副作用。 (如果您不喜欢添加的内容,请随时恢复。)
    • @John1024 .... 实际上工作正常,但仍然需要完整文件的 2 次通过,在我们的文件很大的情况下这需要很多时间。实际上,到目前为止,我们一直在遵循这种方法,并且正在寻找您提供的单通道解决方案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-17
    • 1970-01-01
    相关资源
    最近更新 更多