
我有一個文件,我想提取並重新排列某些數據,舊文件包含原始數據,該文件是輸入
參考:cve,2017-8962 西德:45885 參考:cve,2016-10033 參考:cve,2016-10034 參考:cve,2016-10045 參考:cve,2016-10074 西德:45917 參考:cve,2017-8046 西德:45976 參考:cve,2018-6577 參考:cve,2018-6578 西德:46062
以下文件是包含所需輸出的新文件
參考:cve,2017-8962 西德:45885 參考:cve,2016-10033 西德:45917 參考:cve,2016-10034 西德:45917 參考:cve,2016-10045 西德:45917 參考:cve,2016-10074 西德:45917 參考:cve,2017-8046 西德:45976 參考:cve,2018-6577 西德:46062 參考:cve,2018-6578 西德:46062。
說明:對於範例 sid:45917 有四個引用(reference:cve,2016-10033 reference:cve,2016-10034 reference:cve,2016-10045 reference:cve,2016-10074),我們需要拆分每個引用將一個sid 附加到另一個下面(註:sid 後面總是跟著引用),像這樣有重複的區塊,所以如果有多個引用,我們需要按新檔案順序附加它們。
答案1
正如你似乎使用的事後 sid:
s (多個references:
後跟單一sids:
=> 對references:
和sid:
),兩個解。
解決方案1:倒車
簡單使用tac
命令(它是貓以相反的順序)反轉輸入和輸出:tac input | awk | tac > output
對於 awk 部分,只需複製 s sid:
:
gawk '/^sid:/{sid=$0};/^reference:/{print sid "\n" $0}'
解決方案2:數組
當它們到來時將它們儲存reference:
在一個陣列中,然後當遇到相應的時將它們吐出來sid:
gawk 'BEGIN{r=0};/^reference:/{ref[r++]=$0};/^sid:/{for(n=0;n<r;n++){print ref[n] "\n" $0};r=0}' /tmp/test.txt
/^reference:/{ref[r++]=$0}
:對於以 ref... 開頭的每一行,將該行儲存在陣列中並將「r」指標移到下一個元素。
/^sid:/{for(n=0;n<r;n++){print ref[n] "\n" $0};r=0}
:每當一行以 sid 開頭時,遍歷整個數組直到 r 指標(對於...),對於每個元素,列印儲存的 ref 和當前行(= sid),然後將 r 重置回開頭,以便我們開始再參考下一個參考文獻。
答案2
awk 'BEGIN { i=0; }
/^reference:/ { ref[i++] = $0; }
/^sid:/ { for(j=0; j<i; j++) { print ref[j]; print; } i=0; }' inputfile > outputfile
解釋:
BEGIN { i=0; }
初始化變數以確保它被解釋為數值0
,而不是空字串""
。/^reference:/ { ref[i++] = $0; }
對於以reference:
(^
是行開頭的錨點) 開頭的每一行,將整行複製$0
到數組元素ref[i]
並遞增索引i++
/^sid:/ { ... }
sid:
對於以...開頭的每一行for(j=0; j<i; j++) { ... }
asi
指向最後一個使用的陣列元素之後,循環遍歷已使用 index 寫入的所有陣列元素j
,print ref[j];
列印數組元素的內容,即已儲存的reference:
行print;
列印目前行,即sid:
行i=0;
reference:
將數組索引重設為下一組行的開頭
該腳本基於以下假設:
- 輸入由一系列區塊組成,其中每個區塊包含
- 一行或多行的序列,
reference:
後面接著 sid:
單行
- 一行或多行的序列,
- 最後一行必須是
sid:
一行。 - 不符合的行將被忽略。
對於最初的問題,我假設轉換的方向是錯的。第二個腳本以相反方向轉換:
awk 'BEGIN { oldsid=""; ref=""; }
/^reference:/ { ref=$0; }
/^sid:/ { if(oldsid != $0) { if(oldsid != "") print oldsid; } if(ref!="")print ref; oldsid=$0; }
END { if (oldsid != "") print oldsid; }' inputfile > outputfile
解釋:
BEGIN { oldsid=""; ref=""; }
為了清楚起見初始化變量,並不是真正必要的。/^reference:/ { ref=$0; }
reference:
對於以save the line$0
to variable開頭的每一行ref
,先不要列印它。/^sid:/ { ... }
sid:
對於每行以...開頭的行if(oldsid != $0) { if(oldsid != "") print oldsid; }
如果該行現在已更改,則儲存的sid:
最後一行屬於 new ,因此我們尚未列印它。如果不為空,我們現在可以列印它,因為前面的行塊已經完成。當我們找到第一個時將是空的。reference:
ref
sid:
oldsid
reference:
sid:
oldsid
sid:
if(ref!="")print ref;
如果我們有保存的reference:
,請立即列印。 (要么我們剛剛用相應的行關閉了前一個塊sid:
,要么我們現在知道當前的塊與前一個塊reference:
相同sid:
。)檢查空字串並不是真正必要的,因為我假設每一sid:
行前面都有一行reference:
。oldsid=$0;
儲存目前sid:
行以便在獲得下一行時進行比較。目前行尚未列印。END { if (oldsid != "") print oldsid; }
最後列印最後儲存的sid:
行(如果有)。 (如果輸入檔案為空,則不會在此列印空行。)
該腳本基於以下假設:
- every
reference:
後面跟著一個sid:
- 具有同一行的所有對
reference:
和都相互跟隨sid:
sid: