Awk或Sed:返回两个相同模式之间的行

7
我有一个看起来像这样的文本文件:

-+- beginning text
hey there
hi there
ho there
-+- ending text
other stuff
that is
immaterial for
my purposes

我希望只获取-+-模式之间的行,因此它将返回:
hey there
hi there
ho there

标准的awk方式:

awk '/beginning text/ {flag=1;next} /ending text/ {flag=0} flag {print}'

只要“开始文本”和“结束文本”是不同的模式,就可以很好地工作。
但令人遗憾的是,我需要的“开始文本”和“结束文本”可能会改变。这两行中唯一一致的部分是“-+-”。文件中的所有其他文本都可能完全不同;我不能依赖任何一致的模式。唯一可靠的文本是 -+- 。当两个字符串相同时,awk 失败了。
有没有什么想法可以返回两个离散实例之间的行,而不包括包含模式的行?不一定要使用 awk,只要是在 bash shell 脚本中能工作的东西即可。
4个回答

9
如果模式相同并且您不希望将模式行打印出来,则只需通过每次看到模式时反转标志来组合这两个模式即可。
awk '/^-\+-/ {flag=!flag; next} flag {print}'

哇塞,这真是太简单和太棒了。不知道为什么我没想到过。:) 谢谢Etan。 - Richard D Lawson
3
不错!请注意,您甚至可以省略{print}部分,因为flag评估为True将使awk执行其默认操作:print - fedorqui
1
如果您只需要打印前N个实例:awk '/Matches/ { flag=!flag; count+=1; next } flag && count < 2 {print}' - Murali Suriar

3
cat ttt
aaaa
bbbb
ccccc
bbbb
xxxxx
gggg
awk '/bbb/ {flag=1-flag; next} {if (flag) {print $0}}' ttt
ccccc

3
使用sed命令:
sed -n '/^-+-/,/^-+-/ { /^-+-/! p; }'

使用 awk:

awk '/^-\+-/ { flag++; next } flag % 2'

使用perl

perl -ne 'if (/^-\+-/) { $a ^= 1; next } print if $a'

使用较新的perl
perl -ne 'print if /^-\+-/.../^-\+-/ and !/^-\+-/'

使用 bash:

#! /bin/bash
while IFS= read -r line; do
    if [[ $line =~ ^-\+- ]]; then
        let flag^=1
        continue
    fi
    if [ $flag -ne 0 ]; then
        printf '%s\n' "$line"
    fi
done

输出:

hey there
hi there
ho there

2

针对通用用途(启动/停止相同或不同模式)

awk '#     Start pattern
     $0 ~ /^-\+-/ {flag=1;next}
     #     Stop   pattern
     $0 ~ /^-\+-/ {flag=0;next}

     flag { print}
    ' YourFile

注意:在正则表达式中,+需要进行转义以进行字面使用。
根据@fedorqui的评论进行了调整。

我没有看到这两种模式之间有任何区别。此外,$0 ~ /regex/ 可以简化为 /regex。同样的,可以使用 print 代替 print $0 - fedorqui
在这种情况下,我同意,并回复“任何正则表达式”,在这种特定情况下它是相同的。我假设,扩展问题不会创建2个脚本,这取决于相同或不同的模式(如果出现2个起始/停止模式,则进行适应并简化最后的$0)。 - NeronLeVelu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接