![](/img/trans.png)
[英]awk with AND condition on two patterns misses in between lines which don not match
[英]Can awk patterns match multiple lines?
我有一些復雜的日志文件,需要編寫一些工具來處理它們。 我一直在玩awk,但不確定awk是否適合此工具。
我的日志文件是OSPF協議解碼的打印輸出,其中包含各種協議pkts及其內容的文本日志,以及用值標識的各種協議字段。 我想處理這些文件並僅打印出與特定pkts有關的日志的某些行。 每個pkt日志可以包含該pkt條目的不同行數。
awk似乎能夠處理與模式匹配的一行。 我可以找到所需的pkt,但是接下來我需要在后面的行中匹配模式,以確定它是否是我要打印的pkt。
另一種看待這種情況的方式是,我想隔離日志文件中的幾行,並根據幾行上的模式匹配來打印出這些行,這些行是特定pkt的詳細信息。
由於awk似乎是基於行的,因此我不確定這是否是最好的工具。
如果awk可以做到這一點,怎么做? 如果沒有,關於使用哪種工具的任何建議?
Awk可以輕松檢測模式的多行組合,但是您需要在代碼中創建所謂的狀態機以識別序列。
考慮以下輸入:
how
second half #1
now
first half
second half #2
brown
second half #3
cow
如您所見,很容易識別單個模式。 現在,我們可以編寫一個awk程序,該程序僅在前一半行直接位於后一半時才識別后一半 。 (使用更復雜的狀態機,您可以檢測到任意序列的模式。)
/second half/ {
if(lastLine == "first half") {
print
}
}
{ lastLine = $0 }
如果運行此命令,您將看到:
second half #2
現在,這個例子非常簡單,幾乎沒有狀態機。 有趣的狀態僅在if語句的持續時間內持續,而前一個狀態是隱式的,具體取決於lastLine的值。 在更規范的狀態機中,您將保留一個顯式狀態變量,並根據現有狀態和當前輸入從一個狀態轉換到另一個狀態。 但是您可能不需要那么多的控制機制。
Awk實際上是基於記錄的。 默認情況下,它會將一行視為一條記錄,但是您可以使用RS(記錄分隔符)變量對其進行更改。
解決此問題的一種方法是使用sed進行第一遍(如果願意,也可以使用awk這樣做),以使用換頁符等不同字符來分隔記錄。 然后,您可以編寫awk腳本,在該腳本中將這組行視為一條記錄。
例如,如果這是您的數據:
animal 0
name: joe
type: dog
animal 1
name: bill
type: cat
animal 2
name: ed
type: cat
要使用換頁分隔記錄:
$ cat data | sed $'s|^\(animal.*\)|\f\\1|'
現在,我們將其接受並通過awk。 這是有條件地打印記錄的示例:
$ cat data | sed $'s|^\(animal.*\)|\f\\1|' | awk '
BEGIN { RS="\f" }
/type: cat/ { print }'
輸出:
animal 1
name: bill
type: cat
animal 2
name: ed
type: cat
編輯:作為獎勵,這是使用awk-ward ruby的方法(-014表示使用換頁(八進制代碼014)作為記錄分隔符):
$ cat data | sed $'s|^\(animal.*\)|\f\\1|' |
ruby -014 -ne 'print if /type: cat/'
awk能夠從開始模式處理到結束模式
/start-pattern/,/end-pattern/ {
print
}
我一直在尋找如何搭配
* Implements hook_entity_info_alter().
*/
function file_test_entity_type_alter(&$entity_types) {
如此創造
/\* Implements hook_/,/function / {
print
}
我需要哪些內容。 一個更復雜的示例是跳過線條並擦掉非空間部分。 注意awk是一個記錄(行)和單詞(由空格分割)工具。
# start,end pattern match using comma
/ \* Implements hook_(.*?)\./,/function (.\S*?)/ {
# skip PHP multi line comment end
$0 ~ / \*\// skip
# Only print 3rd word
if ($0 ~ /Implements/) {
hook=$3
# scrub of opening parenthesis and following.
sub(/\(.*$/, "", hook)
print hook
}
# Only print function name without parenthesis
if ($0 ~ /function/) {
name=$2
# scrub of opening parenthesis and following.
sub(/\(.*$/, "", name)
print name
print ""
}
}
希望這也會有所幫助。
另請參見ftp://ftp.gnu.org/old-gnu/Manuals/gawk-3.0.3/html_chapter/gawk_toc.html
我經常用sendmail日志來做這種事情。
鑒於:
Jan 15 22:34:39 mail sm-mta[36383]: r0B8xkuT048547: to=<www@web3>, delay=4+18:34:53, xdelay=00:00:00, mailer=esmtp, pri=21092363, relay=web3., dsn=4.0.0, stat=Deferred: Operation timed out with web3.
Jan 15 22:34:39 mail sm-mta[36383]: r0B8hpoV047895: to=<www@web3>, delay=4+18:49:22, xdelay=00:00:00, mailer=esmtp, pri=21092556, relay=web3., dsn=4.0.0, stat=Deferred: Operation timed out with web3.
Jan 15 22:34:51 mail sm-mta[36719]: r0G3Youh036719: from=<obfTaIX3@nickhearn.com>, size=0, class=0, nrcpts=0, proto=ESMTP, daemon=IPv4, relay=[50.71.152.178]
Jan 15 22:35:04 mail sm-mta[36722]: r0G3Z2SF036722: lost input channel from [190.107.98.82] to IPv4 after rcpt
Jan 15 22:35:04 mail sm-mta[36722]: r0G3Z2SF036722: from=<amahrroc@europe.com>, size=0, class=0, nrcpts=0, proto=SMTP, daemon=IPv4, relay=[190.107.98.82]
Jan 15 22:35:36 mail sm-mta[36728]: r0G3ZXiX036728: lost input channel from ABTS-TN-dynamic-237.104.174.122.airtelbroadband.in [122.174.104.237] (may be forged) to IPv4 after rcpt
Jan 15 22:35:36 mail sm-mta[36728]: r0G3ZXiX036728: from=<clunch.hilarymas@javagame.ru>, size=0, class=0, nrcpts=0, proto=SMTP, daemon=IPv4, relay=ABTS-TN-dynamic-237.104.174.122.airtelbroadband.in [122.174.104.237] (may be forged)
我使用這樣的腳本:
#!/usr/bin/awk -f
BEGIN {
search=ARGV[1]; # Grab the first command line option
delete ARGV[1]; # Delete it so it won't be considered a file
}
# First, store every line in an array keyed on the Queue ID.
# Obviously, this only works for smallish log segments, as it uses up memory.
{
line[$6]=sprintf("%s\n%s", line[$6], $0);
}
# Next, keep a record of Queue IDs with substrings that match our search string.
index($0, search) {
show[$6];
}
# Finally, once we've processed all input data, walk through our array of "found"
# Queue IDs, and print the corresponding records from the storage array.
END {
for(qid in show) {
print line[qid];
}
}
得到以下輸出:
$ mqsearch airtel /var/log/maillog
Jan 15 22:35:36 mail sm-mta[36728]: r0G3ZXiX036728: lost input channel from ABTS-TN-dynamic-237.104.174.122.airtelbroadband.in [122.174.104.237] (may be forged) to IPv4 after rcpt
Jan 15 22:35:36 mail sm-mta[36728]: r0G3ZXiX036728: from=<clunch.hilarymas@javagame.ru>, size=0, class=0, nrcpts=0, proto=SMTP, daemon=IPv4, relay=ABTS-TN-dynamic-237.104.174.122.airtelbroadband.in [122.174.104.237] (may be forged)
這里的想法是,我將打印與要搜索的字符串的Sendmail隊列ID匹配的所有行。 代碼的結構當然是日志文件結構的產物,因此您需要針對要分析和提取的數據自定義解決方案。
`pcregrep -M` works pretty well for this.
從pcregrep(1):
-M,-多行
允許模式匹配多行。 給出此選項后,模式可能會有用地包含文字換行符以及內部出現的^和$字符。 成功匹配的輸出可能包含多行,最后一行是匹配結束的那一行。 如果匹配的字符串以換行符結尾,則輸出在該行的結尾處結束。
設置此選項后,將以“多行”模式調用PCRE庫。 pcregrep在掃描輸入文件時對其進行緩沖的方式對可匹配的行數進行了限制。 但是,pcregrep確保至少有8K個字符或文檔的其余部分(以較短者為准)可用於正向匹配,並且類似地,保證前8K個字符(或所有先前的字符,如果少於8K)也可用。對於后置斷言。 當逐行讀取輸入時,此選項不起作用(請參閱--line-buffered。)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.