【问题标题】:Grep a Log file for the last occurrence of a string between two strings为两个字符串之间最后一次出现的字符串 Grep 一个日志文件
【发布时间】:2013-11-09 23:46:22
【问题描述】:

我有一个日志文件trace.log。在其中,我需要对字符串<tag></tag> 中包含的内容进行grep。这对字符串有多组,我只需要返回最后一组之间的内容(也就是说,来自日志文件的tail)。

额外信用:只有当内容包含“testString”时,我才能返回包含在两个字符串中的内容?

感谢收看。

编辑:搜索参数 和 包含在不同的行中,大约有 100 行内容将它们分开。内容就是我所追求的……

【问题讨论】:

  • 输入示例可能会有所帮助;不清楚标签是在同一行还是在不同的行上。
  • 标签位于不同的行中......我们正在查看标签中大约 70-100 行的内容。
  • 不要将此信息放在 cmets 中,而是更新您的问题。显然,您收到的回复假定标签位于同一行。

标签: unix grep tail


【解决方案1】:

使用tac 以另一种方式打印文件,然后使用grep -m1 仅打印一个结果。向后看和向前看会检查 <tag></tag> 之间的文本。

tac a | grep -m1 -oP '(?<=tag>).*(?=</tag>)'

测试

鉴于此文件

$ cat a
<tag> and </tag>
aaa <tag> and <b> other things </tag>
adsaad <tag>and  last one</tag>

$ tac a | grep -m1 -oP '(?<=tag>).*(?=</tag>)'
and  last one

更新

编辑:搜索参数 和 包含在不同的行中 大约 100 行内容将它们分开。内容就是我 之后……

那就有点棘手了:

tac file | awk '/<\/tag>/ {p=1; split($0, a, "</tag>"); $0=a[1]};
                /<tag>/   {p=0; split($0, a, "<tag>");  $0=a[2]; print; exit};
                p' | tac

这个想法是反转文件并使用标志p 来检查&lt;tag&gt; 是否已经出现。它将在&lt;/tag&gt; 出现时开始打印,并在&lt;tag&gt; 出现时完成(因为我们正在反向读取)。

  • split($0, a, "&lt;/tag&gt;"); $0=a[1]; 获取&lt;/tag&gt; 之前的数据
  • split($0, a, "&lt;tag&gt;" ); $0=a[2];获取&lt;tag&gt;之后的数据

测试

给定一个像这样的文件a

<tag> and </tag>
aaa <tag> and <b> other thing
come here
and here </tag>

some text<tag>tag is starting here
blabla
and ends here</tag>

输出将是:

$ tac a | awk '/<\/tag>/ {p=1; split($0, a, "</tag>"); $0=a[1]}; /<tag>/ {p=0; split($0, a, "<tag>"); $0=a[2]; print; exit}; p' | tac
tag is starting here
blabla
and ends here

【讨论】:

    【解决方案2】:

    如果你像我一样,因为你的系统管理员不会玩球而无法访问 tac,你可以试试:

    grep pattern file | tail -1
    

    【讨论】:

    • 谢谢,这应该是正确的答案。因为 tac 会弄乱输出中的行号,所以 tail -1 成功了
    • also- tact- 不是所有系统的标准
    • 但是请注意,这并没有考虑到 两个字符串之间的部分。
    【解决方案3】:

    grep 之外的另一种解决方案是 sed:

    tac file | sed -n '0,/<tag>\(.*\)<\/tag>/s//\1/p'
    

    tac file 以相反的顺序打印文件(cat 向后),然后sed 从输入行 0 继续到 &lt;tag&gt;.*&lt;\tag&gt; 的第一个出现处,并仅将 &lt;tag&gt;.*&lt;\tag&gt; 替换为在&lt;tag&gt; 里面。 p 标志打印输出,该输出被 -n 抑制。

    编辑:如果 &lt;tag&gt;&lt;/tag&gt; 在不同的行上,这将不起作用。我们仍然可以使用sed

    tac file | sed -n '/<\/tag>/,$p; /<tag>/q' | sed 's/.*<tag>//; s/<\/tag>.*//' | tac
    

    我们再次使用tac 向后读取文件,然后第一个sed 命令从第一次出现的位置读取并在找到时退出。只打印中间的行。然后我们将它传递给另一个sed 进程以去除's,最后用tac 再次反转行。

    【讨论】:

      【解决方案4】:

      一个处理多行的未测试小awk:

      awk '
          BEGIN    {retain="false"}
          /<\tag>/ {retain = retain + $0; keep="false"; next}
          /<tag>/  {keep = "true"; retain = $0; next}
          keep == "true" {retain = retain + $0}
          END {print retain}
      ' filename
      

      我们开始只是读取文件;当我们点击 时,我们开始保持线条。当我们击中 时,我们停止。如果我们点击另一个,我们清除保留的字符串并重新开始。如果您想要所有字符串,请在每个

      处打印

      【讨论】:

        【解决方案5】:
        perl -e '$/=undef; $f=<>; push @a,$1 while($f=~m#<tag>(.*?)</tag>#msg); print $a[-1]' ex.txt
        

        额外积分:我可以通过任何方式返回包含在 仅当内容包含“testString”时才两个字符串?

        perl -e '$/=undef; $f=<>; push @a,$1 while($f=~m#<tag>(.*?)</tag>#msg); print $a[-1] if ($a[-1]~=/teststring/);' ex.txt
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-01-27
          • 2015-05-11
          • 1970-01-01
          • 1970-01-01
          • 2016-10-09
          • 1970-01-01
          • 2015-05-12
          • 2019-11-27
          相关资源
          最近更新 更多