grep 一个模式在另一个模式之前最后一次出现的位置

grep 一个模式在另一个模式之前最后一次出现的位置

我有一个巨大的文件包含两种类型的模式说模式1模式2, 模式1之前可能出现过很多次模式2出现。我想 grep 每个的最后一次出现模式1在每个之前模式2

输入文件:

some text
pattern1=1
some lines
pattern1=2
some lines
pattern1=3
some lines
pattern2
some lines
pattern1=4
some lines
pattern1=5
some lines
pattern1=6
some lines
pattern1=7
some lines
pattern2

期望的输出:

pattern1=3
pattern1=7

grep当我知道之间的行数时我尝试过模式2和上一个模式1

grep -B400 "pattern2" | grep "pattern1"

但我需要一个可以在任何文件上运行的独特命令,无论两个模式之间的行数如何。

答案1

$ awk '/pattern1/{x=$0} /pattern2/{print x}' input
pattern1=3
pattern1=7

将匹配项(整行)保存pattern1到变量中x并在pattern2发生时打印该匹配项。如果在pattern2任何之前有一个空行,则将打印一个空行pattern1,这将需要更多的逻辑来检测这是否是不可取的。将删除输入末尾之前pattern1未跟有 a 的所有尾随。pattern2

答案2

@thrig 的答案很好,但我做了一些修改来处理一些额外的测试用例。以下脚本:

  • pattern2如果出现在 第一次出现之前,则不会打印空行pattern1
  • pattern2如果在 后多次出现,则不会打印重复行pattern1

修改后的输入文件:

pattern2
some text
pattern1=1
some lines
pattern1=2
some lines
pattern1=3
some lines
pattern2
pattern2
some lines
pattern1=4
some lines
pattern1=5
pattern2
some lines
pattern1=6
some lines
pattern1=7
some lines
pattern2

以下脚本似乎执行您在文中描述的操作:

$ awk '/pattern1/{x=$0} length(x) && /pattern2/{print x;x=""}' file
pattern1=3
pattern1=5
pattern1=7

答案3

三个grep调用:

  1. 仅从原始输入文件中提取与^pattern1=或匹配的行^pattern2$

    grep -e '^pattern1=' -e '^pattern2$' file
    
  2. 获取匹配的行^pattern2$,以及紧邻这些行之前的行(使用非标准-B选项):

    grep -B1 '^pattern2$'
    
  3. 获取所有匹配的行^pattern1=

    grep '^pattern1='
    

全部一起:

grep -e '^pattern1=' -e '^pattern2$' file |
grep -B1 '^pattern2$' |
grep '^pattern1='

这处理与以下相同的边缘情况用户000001的回答,即如果有许多pattern2行之间没有pattern1行,它不会输出重复行,并且不会为pattern2文件开头的行生成空行。


使用sed

sed -e '/^pattern1=/ { h; d; }' \
    -e '/^pattern2$/ x' \
    -e '/^pattern1=/ !d' file
  1. 如果当前行是pattern1一行,则将其保存到保留空间中并丢弃它。

  2. 如果当前行是pattern2一行,则它会交换保留空间。

  3. 如果当前行现在不是一行pattern1,则将其丢弃。

  4. (隐式)打印当前行。通过前面的命令,当前行必须是pattern1由于查找pattern2行而从保留空间换入的行。因此,保留空间必然会保留一行pattern2,确保该pattern1行不会被多次输出。

答案4

egrep "^pattern1|^pattern2" <file> | grep -B 1 "^pattern2" | grep "^pattern1"

第一个 egrep 将仅获取包含任一模式的行(从输出中剥离所有其他未知行)。第二个 grep 将获取pattern2 及其前面的任何行。这将用于删除模式 2 之前没有模式 1 的行。第三个 grep 将只返回剩余的pattern1 行。

相关内容