2017-06-14 65 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