bash在pattern1的第一次出现和pattern2的最后出现之间搜索文本

时间:2017-11-07 14:39:24

标签: bash awk sed

我试图获得第一次出现pattern1和最后一次出现模式2之间的所有行,这两种模式都是正则表达式

示例代码

TEXT
TEXT
[SUN_START]
[SUN_END]

[MON_START]
TEXT
[MON_END]

[TUE_START]
[TUE_END]

[WED_START]
TEXT
[WED_END]
TEXT
TEXT

我期待的输出是

[SUN_START]
[SUN_END]

[MON_START]
TEXT
[MON_END]

[TUE_START]
[TUE_END]

[WED_START]
TEXT
[WED_END]

模式为XXX_START和XXX_END

到目前为止我得到的是

cat /u01/app/oracle/admin/LNOPP1P/config/dbbackup_LNOPP1P.config | sed -n -e '/[[A-Z][A-Z][A-Z]_START]/,/[[A-Z][A-Z][A-Z]_END]/p'

但这不会保留换行符并像这样显示所有内容

[SUN_START]
[SUN_END]
[MON_START]
TEXT
[MON_END]
[TUE_START]
[TUE_END]
[WED_START]
TEXT
[WED_END]

我还想确保它只匹配以[[A-Z] _START]开头的行和与END

相同的行

4 个答案:

答案 0 :(得分:1)

awk应该有效:

awk '/_START\]/{p=1} p{a = a $0 ORS}/_END\]/{printf "%s", a; a="";}' file

简单逻辑:

  1. 在第一个* _START标记处,启用p = 1。这将在第一个* _START标记之前丢弃这些行。
  2. 对于每一行,将当前行附加到本地变量。
  3. 在每个* _END标记处,打印局部变量并清空它。
  4. 由于我们仅在* _END标记处打印,因此不打印最后一个* _END之后的那些行。

答案 1 :(得分:1)

使用awk

的没有grep的解决方案
grep -Pzo '(?s)\[([A-Z]{3})_START\].*\n.*\[\1_END\]' file | sed 's/\x00/\n\n/'

你明白了,

[SUN_START]
[SUN_END]

[MON_START]
TEXT
[MON_END]

[TUE_START]
[TUE_END]

[WED_START]
TEXT
[WED_END]

*基于@albfan answer

答案 2 :(得分:0)

您可以使用awk

awk '/\[..._START\]/{p=1}/\[..._END\]/{print;p=0}p||!NF' file

需要打印时设置变量p!NF允许保留空行。

答案 3 :(得分:0)

恕我直言,在不保存内存内容的情况下采用两遍方法是最简单,最强大的方法:

$ awk '
    NR==FNR { if (/\[[A-Z]+_START\]/ && !beg) beg=NR; if (/\[[A-Z]+_END\]/) end=NR; next }
    FNR>=beg && FNR<=end
' file file
[SUN_START]
[SUN_END]

[MON_START]
TEXT
[MON_END]

[TUE_START]
[TUE_END]

[WED_START]
TEXT
[WED_END]

考虑使用[[:upper:]]代替[A-Z]来跨区域设置进行移植。

我刚看到你在不同的答案下发表了这个评论:

Is it simple to invert this selection? select everything but the bit selected by this AWK ?

,答案是&#34;当然&#34;,只需更改脚本末尾的条件:

$ awk '
    NR==FNR { if (/\[[A-Z]+_START\]/ && !beg) beg=NR; if (/\[[A-Z]+_END\]/) end=NR; next }
    FNR<beg || FNR>end
' file file
TEXT
TEXT
TEXT
TEXT

或保持原始状态,但要做出动作&#34;接下来&#34;并添加默认&#34;打印&#34;对于其他每一行:

$ awk '
    NR==FNR { if (/\[[A-Z]+_START\]/ && !beg) beg=NR; if (/\[[A-Z]+_END\]/) end=NR; next }
    FNR>=beg && FNR<=end { next }
    { print }
' file file
TEXT
TEXT
TEXT
TEXT