Perl one liner来模拟awk脚本

时间:2017-06-14 11:57:32

标签: perl awk range

我对awkperl都是新手,所以请耐心等待。 我有以下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年5月24日17:00:06,827 [INFO] 123456(Blah:Blah1)服务名称::单行内容

     

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

     

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

     

2017年5月24日17:00:06,830 [INFO] 123456(Blah:Blah1)服务名称::单行内容

     

2017年5月24日17:00:06,831 [INFO] 567890(Blah:Blah2)服务名称::内容(可跨越多行)

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

  

2017年5月24日17:00:06,827 [INFO] 123456(Blah:Blah1)服务名称::单行内容

     

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

     

2017年5月24日17:00:06,830 [INFO] 123456(Blah:Blah1)服务名称::单行内容

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

2 个答案:

答案 0 :(得分:2)

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

这有点疯狂,但这是它的工作原理:

  • -n在输入行上添加隐式循环
  • 当前行位于$_
  • 两个裸正则表达式匹配(/regex2//regex1 /)隐式测试$_
  • 我们在标量上下文中使用..,将其转换为有状态的触发器运算符

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

    在“true”状态下,它仅评估Y。如果Y返回false,则它保持“true”状态(并返回true本身)。一旦Y返回一个真值,它就会进入“假”状态但它仍然返回true。

  • 如果我们刚刚使用print if /regex2/ .. /regex1/,它也会打印所有终止regex1

  • 仔细阅读Range Operators in perldoc perlop表明您可以区分范围的终点
  • ..返回的“true”值实际上是从1开始的序列号,因此可以通过检查1
  • 来识别范围的开头
  • 当达到范围的结尾时(即我们将要再次从“true”状态转移到“false”状态),返回值将被加"E0"结束

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

  • ..返回的“false”值为空字符串""

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

答案 1 :(得分:0)

不确定awk是否同时打印范围的开头和结尾,但Perl会:

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

编辑:Awk(至少Gnu awk)也有一个范围运算符,所以这可以更简单地完成:

awk '/regex2/,/regex1/' file