Text-Processing
如何按類別辨識、降序排序和顯示前 10 個文本塊
在我們系統內的實體上完成的交易歷史如下所示:
1 BYM1 TSTAB 09NOV 0035 CAB Sometext 01 2 BYM1 TSTAB 09NOV 0035 CAB Can be done - question 3 BYM1 TSTAB 09NOV 0035 CAB Sometext 02 Sometext 03 6 BYM3 TSTAA 09NOV 0400 CAA Some 04 text 04 7 BYM3 TSTAA 10NOV 0455 CAC Sometext 06 Sometext 06 line 2 8 BYM3 TSTAA 10NOV 0455 CAC Sometext 07 9 BYM2 TSTAC 10NOV 0619 CAD Some 08 text 0008 ABCD Some 08 text 0008 BB00 Some 08 text 0008 CC00 Some 08 text 0008 DD00 Some 08 text 0008 EE00 10 BYM2 TSTAC 10NOV 0627 CAD Something BBBBBSSDGFSDSF 11 BYM2 TSTAC 10NOV 0627 CAD Something else 12 BYM2 TSTAC 10NOV 0627 CAD What text here 13 BYM4 TSTAC 10NOV 0711 CAD Tired figuring out 19 BYM3 TSTAA 11NOV 0438 CAE Some 04 text 05 05 05 20 BYM3 TSTAA 11NOV 0441 CAF Not so confidential now 21 BYM3 TSTAA 11NOV 0441 CAF Some 00 text 0009 X1X2 43 BYM3 TSTAA 11NOV 0441 CAD Some 0A text 0009 ABCD 44 BYM3 TSTAA 11NOV 0441 CAD Some 1B text 45 BYM3 TSTAA 12NOV 1455 CAC Something 0AADDBB 8782 BYM3 TSTAA 12NOV 1610 CAD Something 0AADDBB 8830 BYM3 TSTAA 12NOV 1612 CAA Something 0AADDBB 9999 BYM3 TSTAA 12NOV 1722 CAA Something 0AADDBB
文本塊從前 4 個字元中有數字的行開始。(這個數字實際上是一個正在執行的序列號,每個事務都用它來索引)。塊的(交易的)類別由具有數字的行中的最後三個字元定義。
我正在尋找一個 awk, sed (, vi, grep) 腳本來搜尋屬於“類別”的文本塊,按索引(數字)的降序對結果塊進行排序,顯示我問過的塊數為了。
例如,如果我想搜尋 4 個類別“CAD”的塊,我想看到的輸出是:
8782 BYM3 TSTAA 12NOV 1622 CAD Something 0AADDBB 44 BYM3 TSTAA 11NOV 0441 CAD Some 1B text 43 BYM3 TSTAA 11NOV 0441 CAD Some 0A text 0009 ABCD 13 BYM4 TSTAC 10NOV 0711 CAD Tired figuring out
我怎樣才能做到這一點。任何幫助將不勝感激 :-)
遵循 linux 原則“一個任務——一個工具”:
- 僅列印必要的塊(如範例
CAD
)
sed '/^\s*[0-9].*CAD/!d;:a;N;/\n\s*[0-9]/! s/\n/\x0/;ta;P;D'
2. 倒序排列
sort -rn
3. 取第一個詢問的塊(如範例4
)
head -4
請注意,大多數 linux 命令使用行(而不是blocks)操作,因此通過將
\n
ew line 更改為 null-symbol( ) 將這些命令轉換為行,然後通過tr\x0
轉換回來。所以,所有線路:sed '/^\s*[0-9].*CAD/!d;:a;N;/\n\s*[0-9]/! s/\n/\x0/;ta;P;D' test.txt | sort -rn | head -4 | tr '\0' '\n'
我喜歡G-Man answer改變
R
owS
eparator 的想法,但這不太適合這種情況。用普通方法做更簡單awk ' /^[ 0-9]{4} /{ #for start block string if($NF==cat){ #if it is a needed block idx=$1 BLOCK[idx]=$0 #put line onto array with asigned index } else idx=0 #otherways asign index to 0 next #end itteration, go to start with next line } idx{ #pass inappropriate blocks (with 0-index) BLOCK[idx]=BLOCK[idx] "\n" $0 #add line to array element with index } END{ #when finish all lines for(i=0;i<num;i++){ #do num times max=0 #asing `max` variable to min value for(idx in BLOCK){ #for each index in array idx=idx+0 #convert string index into decimal if(idx>max) max=idx #find maximum index (field No.1 in block) } if(!max) exit #exit script if array empty (no more blocks) print BLOCK[max] #print block with maximum index delete BLOCK[max] #remove array element for furure search } }' cat="CAD" num=4 test.txt
這是 gawk 的解決方案(GNU
awk
;即awk
大多數“Linux”系統上的版本)。假設$cat
設置為您要搜尋的類別,並$num
設置為您要顯示的記錄數。awk -vRS='\n[ 0-9][ 0-9][ 0-9][0-9] ' -vcat="$cat" -vnum="$num" \ ' BEGIN { first=1; rec_ind=0} { if (first) { rec = $0 first=0 } else { rec = save_seq $0 } findnl = index(rec, "\n") if (findnl < 7) exit thiscat = substr(rec, findnl-3, 3) if (cat == thiscat) records[++rec_ind] = rec if (length(RT) == 0) { # print "This should be the last record." save_seq = "Does not matter" } else if (length(RT) == 6) { save_seq = substr(RT, 2, 5) } else { print "Invalid RT: len =", length(RT) exit } } END { num_recs = asort(records, sorted_records, "@val_num_desc") if (num < num_recs) num_recs = num for (i=1; i<=num_recs; i++) { print sorted_records[i] } } '
筆記:
-vRS='\n[ 0-9][ 0-9][ 0-9][0-9] '
將 awk 的 RS(記錄分隔符)變數設置為由換行符組成的正則表達式,後跟最多四位的整數序列號,後跟一個空格。我包含換行符是因為您的數據在行的內部有四位數字(後跟空格),它們不會被解釋為記錄分隔符。請注意,這個正則表達式有點草率,因為它會接受007
and12 4
。將此設置為 awk 的記錄分隔符意味著您的每個“事務”都將被視為單個 awk 記錄,即使它包含多行。有幾個缺點:
- 由於 RS 模式在開頭包含換行符,因此
1
數據開頭的 將不會被辨識為記錄分隔符。- 由於這是記錄分隔符模式,因此它不被視為記錄的一部分,即使它包含重要資訊。我們會處理這些問題。
-vcat="$cat"
並-vnum="$num"
類似地設置 awk 變數cat
和num
相應 shell 變數的值。BEGIN { first=1; rec_ind=0}
將標誌初始化first
為真(1),因此我們可以辨識第一條記錄並對其進行特殊處理,並將記錄索引(rec_ind
)設置為0,用於累積匹配所需類別的記錄。if (first)
為真(我們正在處理第一條記錄),設置rec
為等於 awk 記錄,$0
. 請記住,這包括直到(但不包括)以四位數開頭的下一行的所有行。此外,它還包括第一行開頭的四位數字。然後我們將first
標誌設置為假(0)。如果這不是第一條記錄,那麼它缺少它的四位數字(因為那是記錄分隔符),所以我們
rec
通過將保存的序列號 (save_seq
) 與連接來構造記錄 ( )$0
。(我會save_seq
暫時討論。)
findnl = index(rec, "\n")
查找記錄中的第一個換行符(請記住,記錄包含多行)。如果從頭到尾少於 7 個字元,那麼序號和類別(沒有重疊)就沒有空間,更不用說其他欄位了,所以這是一個錯誤。否則,從第一個換行符之前的最後三個字元中提取此記錄的類別 (thiscat
),即事務第一行的最後三個字元。然後,如果thiscat
匹配我們正在尋找的類別,則將記錄保存在records
數組中。RT
是記錄終止符——與RS
目前記錄末尾的模式匹配的字元。不幸的是,目前記錄的終結者實際上是下一個記錄的開始。如果目前記錄是最後一條,則為RT
空字元串(長度為 0);否則,它應始終為 6 個字元長(一個換行符、四個空格或數字字元以及一個空格)。提取最後五個字元(即丟棄換行符)並將其另存為save_seq
,因為它是下一個事務的序列號。- 當我們到達數據的末尾時,對記錄進行排序(對值進行排序,將它們視為數字,按降序排列)。然後列印
num
它們。