使用sed/awk在锚点之间抓取文本(可以重复)而不是锚点



--AnchorABC可以重复1-N时如何获得--AnchorABC--Anchor<not ABC>之间的内容的任何想法?

示例输入:

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(,但是有一个奇数,那么hack会分解。使用SED,我试图在--AnchorABC和以--开头但不是的范围内的线之间进行模式范围,但是SED没有负面的lookahead。

基本上问题语句是:在第一次出现以--开头的模式之间,在--之后的键,然后是任意结局,然后是一个以模式--开头的行,但以一个键,但以一个键不同的键。或另一种方式:

  • 匹配--AnchorABC
    • 如果后续行与--AnchorABC匹配或不以--开头的任何东西,请打印
    • 如果一条线与--Anchor匹配,但不是--AnchorABC,请停止

编辑:清楚地表明,第二个锚键尚不清楚,并且"键"可以是多个字符。

使用awk:

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是一个尴尬的技巧:它表示true,在真实条件下,awk默认值是打印。
  • 第二个//{}的同一件事,但我们使用负范围排除字符A当l = 1在stdout上打印1时,当l = 0时,它不是

如果您不需要否定字符,而是字符串

然后,佩尔(Perl

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

检查环顾四周(您可以用字符串替换A,而不仅仅是字符(

或保持尴尬:

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

sed用于单个行上的简单替换,即全部。对于其他任何东西,您应该使用尴尬:

$ 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/} =当前行以--开头时,如果该行包含--AnchorABC0,则将标志f设置为1,否则。
  2. f在末尾=如果将标志 f设置为 1,则agk发生默认操作是要打印当前行。

我想出了一个令人讨厌的SED解决方案,尽管我更喜欢Gilles的尴尬解决方案来可读性:

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

这可能对您有用(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标志允许^'分别匹配一条线的开始和模式空间的末端。

这是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
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

解决方案将grepsed>负LookAhead

$ 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. $(tail -n +$A input.file |grep -Pnm1 '^--Anchor(?!ABC)' | cut -d':' -f1)从第一次出现中,您可以找到多少行,直到达到符合'^--Anchor(?!ABC)'条件的线,并且您相对于'^--AnchorABC'的第一次出现
  3. 相对获得其线号。
  4. 您仅用sed -n "$A,+$((B-1)) p" input.file
  5. 打印所讨论的范围

最新更新