25

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

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

感谢您的关注。

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

4

5 回答 5

34

用于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来检查是否<tag>已经出现。它会在出现时开始打印并在</tag>出现时完成<tag>(因为我们正在阅读相反的方式)。

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

测试

给定这样的文件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
于 2013-10-30T12:03:58.260 回答
26

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

grep pattern file | tail -1
于 2014-11-12T11:03:38.753 回答
1

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

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

tac file以相反的顺序(cat向后)打印文件,然后sed从输入行0继续到 的第一次出现,并仅用里面的部分<tag>.*<\tag>替换。该标志打印输出,该输出被 抑制。<tag>.*<\tag><tag>p-n

<tag>编辑:如果并且</tag>在不同的行上,这不起作用。我们仍然可以使用sed

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

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

于 2013-10-30T12:13:23.080 回答
0
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
于 2013-10-30T12:11:00.417 回答
0

一个处理多行的未经测试的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

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

于 2013-10-30T12:36:17.643 回答