我有一个巨大的文件包含两种类型的模式说模式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
调用:
仅从原始输入文件中提取与
^pattern1=
或匹配的行^pattern2$
grep -e '^pattern1=' -e '^pattern2$' file
获取匹配的行
^pattern2$
,以及紧邻这些行之前的行(使用非标准-B
选项):grep -B1 '^pattern2$'
获取所有匹配的行
^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
如果当前行是
pattern1
一行,则将其保存到保留空间中并丢弃它。如果当前行是
pattern2
一行,则它会交换保留空间。如果当前行现在不是一行
pattern1
,则将其丢弃。(隐式)打印当前行。通过前面的命令,当前行必须是
pattern1
由于查找pattern2
行而从保留空间换入的行。因此,保留空间必然会保留一行pattern2
,确保该pattern1
行不会被多次输出。
答案4
egrep "^pattern1|^pattern2" <file> | grep -B 1 "^pattern2" | grep "^pattern1"
第一个 egrep 将仅获取包含任一模式的行(从输出中剥离所有其他未知行)。第二个 grep 将获取pattern2 及其前面的任何行。这将用于删除模式 2 之前没有模式 1 的行。第三个 grep 将只返回剩余的pattern1 行。