使用sed / awk在锚点(可以重复)而不是锚点

时间:2018-02-14 00:04:53

标签: awk sed

--AnchorABC重复1次时,有关如何在--Anchor<not ABC>--AnchorABC之间获取内容的任何想法?

示例输入:

It
is
a
lovely
day
--AnchorABC something
--AnchorABC something else
--AnchorABC yet something else
Hey
how 
are
you
--AnchorXYZ
I 
am
fine
--AnchorLMN

示例输出(删除最后一行不是非常重要):

--AnchorABC something
--AnchorABC something else
--AnchorABC yet something else
Hey
how 
are
you
--AnchorXYZ

如果偶数--AnchorABC那么它很容易(尽管是hacky),但是有一个奇数,那么黑客就会崩溃。使用sed,我试图在--AnchorABC和以--开头但的行具有AnchorABC的行之间进行模式范围,但是sed没有负向前瞻。

基本上问题陈述是:在第一次出现的模式之间打印所有行,这些模式以--开头,并且在--之后有一个键,然后是一个任意结尾,下一次出现一行从模式--开始,但使用不同的密钥。或者另一种方式:

  • 匹配--AnchorABC
    • 如果后续行符合--AnchorABC或任何不以--开头的内容,请将其打印
    • 如果某行符合--Anchor但不是--AnchorABC,请停止

编辑:明确表示第二个锚键未知,“键”可以是多个字符。

7 个答案:

答案 0 :(得分:3)

使用

awk '/^--AnchorA/{l=1} /^--Anchor[^A]/{l=0; print; exit}l' file.txt

或者更简单,感谢@iamuser的想法:

awk '/^--AnchorA/{l=1}; l; /^--Anchor[^A]/{exit}' file.txt

说明:

  • //{} =正则表达式条件和执行
  • 所以/^--AnchorA/{l=1}表示如果正则表达匹配则分配l=1
  • 中间的l是一个awk技巧:它意味着true,而在真实情况下,awk默认是打印。
  • 第二个//{}同样的事情,但我们使用负范围来排除字符A 当l = 1时,在STDOUT上打印awk,当l = 0时,它不会

如果你需要否定一个字符而不是一个字符串

然后来拯救环顾正则表达式高级技术:

perl -ne 'print if /^--AnchorA/ .. /^--Anchor(?!A)/' file.txt

检查look around(您可以用字符串替换A,而不仅仅是字符)

或保留

awk '
    /^--AnchorA/{l=1;print;next};
    l;
    /^--Anchor/ && $0 !~ /^--AnchorABC/ {exit}
' file.txt

答案 1 :(得分:1)

虽然我更喜欢Gilles&#39;但我找到了一个令人讨厌的解决方案。 解决方案的可读性:

sed -ne "/^--AnchorA/{p;                                                                                         
                      :loop
                      n;
                      p;
                      /^--/{/^--AnchorA/\!q};
                      b loop}" testfile | sed '$d'

答案 2 :(得分:1)

这可能适合你(GNU sed):

sed -nr '/^--AnchorABC/{:a;N;/^--AnchorABC[^\n]*\'\''/Mba;/^--Anchor[^\n]*\'\''/M!ba;p}' file

使用GNU seds多行结束字符串\'(此处显示为\'\'',因为该命令是单引号)。这会使用N收集多行,如果附加的最后一行是--AnchorABC,则会继续追加,直到开始--Anchor并且不继续ABC的行然后打印该集合并重复。

N.B。 Seds M标志允许^\'分别匹配行的开头和模式空间的结尾。

答案 3 :(得分:1)

sed用于单个行上的简单替换,全部。对于其他任何你应该使用awk:

$ awk '/^--/{f=/--AnchorABC/} f' file
--AnchorABC something
--AnchorABC something else
--AnchorABC yet something else
Hey
how
are
you

可以调整它来打印终止的非匹配线,但你说having the last line deleted isn't super important所以我没有打扰。

说明:

  1. /^--/{f=/--AnchorABC/} =当前行以--开头时,如果该行包含f1,则会将标记--AnchorABC设置为0否则。
  2. f在最后拥有它=如果标志f设置为1,那么就打开 发生默认操作,即打印当前行。

答案 4 :(得分:0)

这是一个awk解决方案,

 $ awk '/AnchorA/{a=1};a;/AnchorB/{exit}' file

这是一个sed解决方案,

$ sed '/AnchorA/,/AnchorB/!d;/AnchorB/q' file

输出(两种情况):

--AnchorA something
--AnchorA something else
--AnchorA yet something else
Hey
how 
are
you
--AnchorB

答案 5 :(得分:0)

awk -v search="AnchorABC" '
                           BEGIN{r="^[-]+"search}
                           $0~r{f=1}f;
                           /^[-]+/ && $0 !~ r{exit}
                          ' file

测试结果:

<强> 输入:

$ cat file
It
is
a
lovely
day
--AnchorABC something
--AnchorABC something else
--AnchorABC yet something else
Hey
how 
are
you
--AnchorXYZ
I 
am
fine
--AnchorLMN

输出:

$ awk -v search="AnchorABC" 'BEGIN{r="^[-]+"search}$0~r{f=1}f;/^[-]+/ && $0 !~ r{exit}' file
--AnchorABC something
--AnchorABC something else
--AnchorABC yet something else
Hey
how 
are
you
--AnchorXYZ

答案 6 :(得分:0)

grepsed否定前瞻混合的解决方案:

$ A=$(grep -Pnm1 '^--AnchorABC' input.file | cut -d':' -f1); B=$(tail -n +$A input.file |grep -Pnm1 '^--Anchor(?!ABC)' | cut -d':' -f1); sed -n "$A,+$((B-1)) p" input.file 
--AnchorABC something
--AnchorABC something else
--AnchorABC yet something else
Hey
how 
are
you
--AnchorXYZ

<强>说明:

  1. $(grep -Pnm1 '^--AnchorABC' input.file | cut -d':' -f1)找到第一次出现--AnchorABC
  2. 的行号
  3. $(tail -n +$A input.file |grep -Pnm1 '^--Anchor(?!ABC)' | cut -d':' -f1)从第一次出现后,您会找到多少行,直到达到符合'^--Anchor(?!ABC)'条件的行,并且您的行号相对于第一次出现'^--AnchorABC'
  4. 您只使用sed -n "$A,+$((B-1)) p" input.file
  5. 打印相关范围