2017-06-14 83 views
0

我是awkperl的新手,请耐心等待。 我有以下awk脚本:Perl单线程模拟awk脚本

awk '/regex1/{p = 0;} /regex2/{p = 1;} p' 

什么这通常做的就是打印从regex2线匹配盯着所有行直到regex1的线路匹配被发现。

实施例:

regex1 
regex2 
line 1 
line 2 
regex1 
regex2 
regex1 

输出:

regex2 
line 1 
line 2 
regex2 

是否有可能使用perl单行来模拟此?我知道我可以用一个保存在文件中的脚本来做到这一点。

编辑:

一个实际的例子:

2017 17年5月24日:00:06827 [INFO] 123456(布拉赫:Blah1)服务名称::单线内容

24 2017年5月17日17:00:06,828 [信息] 567890(Blah:Blah1)服务名称::内容(可能包含多行)

2017年五月24日17:00:06,829 [INFO] 123456(Blah:Blah2) 服务名称:多行内容。印刷对象物[ID1 = FAC-adasd ID2 = 123231
ID3 = 123108个状态=未知
代码= 530007站Dest = CA
]

2017 17年5月24日:00:06830 [INFO] 123456(布拉赫: Blah1)服务名称::单线内容

24 2017 5月17日:00:06831 [INFO] 567890(布拉赫:Blah2)服务名称::含量(可跨越多行)

鉴于搜索键123456我想提取以下内容:

2017 17年5月24日:00:06827 [INFO] 123456(布拉赫:Blah1)服务名称::单线内容

2017 17年5月24日:00:06829 [INFO] 123456(布拉赫: Blah2) 服务名称:多行内容。印刷对象物[ID1 = FAC-adasd ID2 = 123231
ID3 = 123108个状态=未知
代码= 530007站Dest = CA
]

2017 17年5月24日:00:06830 [INFO] 123456(布拉赫: Blah1)服务名称::单线内容

以下awk脚本做这项工作:
awk '/[0-9]{2}\s\w+\s[0-9]{4}/{n = 0} /123456/ {n =1}n' file

+0

你知道有一个你可以尝试的程序awk2perl吗? – JFS31

+0

为awk,请参阅https://stackoverflow.com/a/38972737/4082052更好的方法......如果您知道如何编写perl脚本,请参阅https://stackoverflow.com/documentation/perl/3696/perl- one-liners#t = 201706141257567028325和http://perldoc.perl.org/perlrun.html#Command-Switches ..你会想要使用http://perldoc.perl.org/perlop.html#Range-Operators – Sundeep

回答

2
perl -ne 'print if (/regex2/ .. /regex1/) =~ /^\d+$/' 

这稍微疯狂的,但这里的工作原理是:

  • -n在输入线增加了一个隐含的循环
  • 当前行是在$_
  • 两个裸正则表达式匹配(/regex2//regex1 /)隐式测试针对$_
  • 我们使用..在标量上下文,它把它变成一个有状态的触发器操作者

    我的意思是:X .. Y从“假”状态开始。在“假”状态下,它只评估X。如果X返回一个假值,它将保持“假”状态(并自身返回false)。一旦X返回一个真值,它将进入“真”状态并返回true。

    在“真实”状态下,它只评估Y。如果Y返回false,它将保持“true”状态(并自身返回true)。一旦Y返回一个真值,它将进入“假”状态,但它仍然返回true。

  • 了,我们只是用print if /regex2/ .. /regex1/,它会打印所有的终端regex1线,太

  • Range Operators in perldoc perlop仔细阅读发现,你能分辨的范围
  • “真”值的终点通过..返回实际上是从1起始序列号,等等一系列的启动可以通过检查1
  • 达到范围的结束时被识别(即我们将要在“真”动状态“false”状态),返回值获得"E0"结尾

    "E0"添加到整数不会影响其数值。 Perl会在需要时将字符串隐式转换为数字,而"5E0"就是科学记数法(意思是5 * 10**0,即5 * 1,即5)。

  • “假”的..返回的值是空字符串,""

我们检查的..结果相匹配的正则表达式/^\d+$/,即是所有数字。这不包括空字符串(因为我们至少需要一位数字来匹配),所以我们不会在范围之外打印行。它也排除我们范围的最后一行,因为E不是一个数字。

+0

感谢您的解释。这确实是疯了。我在问题中给出了一个非常一般的例子,代码的工作原理。我还需要打印regex1和regex2位于同一行的情况(优先考虑regex2)。但是我相信我可以自己做到这一点,这要感谢你的解释。 – gitmorty

+0

@AkhilAvinash听起来像是可以用'my $ p =/regex2/../regex1 /打印如果$ p &&($ p == 1 || $ p!〜/ E /);' – melpomene

+0

不,这并没有完成这项工作。当我们有一行'regex1 regex2'时,它只打印那行,而不打印行,因为$ p的值在行本身内部设置为1E0。我相信每个$ _都与/ regex2 /和/ regex1 /匹配,因此范围在行本身内部结束。让我知道是否有办法解决这个问题。 – gitmorty

0

不知道awk的打印都开始和结束的范围内,但Perl的作用:

perl -ne 'if(/regex2/ ... /regex1/){print}' file 

编辑:在awk(至少了GNU AWK)还具备一系列操作,所以这可能是更简单的实现为:

awk '/regex2/,/regex1/' file 
+0

我实际上需要脚本来打印开始和中间的行,不包括范围的结尾。 awk脚本就是这样做的。有没有办法修改你的perl单行版来做同样的事情? – gitmorty