從文件中提取並重新排列

從文件中提取並重新排列

我有一個文件,我想提取並重新排列某些數據,舊文件包含原始數據,該文件是輸入

參考: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 $0to variable開頭的每一行ref,先不要列印它。
  • /^sid:/ { ... }sid:對於每行以...開頭的行
  • if(oldsid != $0) { if(oldsid != "") print oldsid; }如果該行現在已更改,則儲存的sid:最後一行屬於 new ,因此我們尚未列印它。如果不為空,我們現在可以列印它,因為前面的行塊已經完成。當我們找到第一個時將是空的。reference:refsid:oldsidreference:sid:oldsidsid:
  • if(ref!="")print ref;如果我們有保存的reference:,請立即列印。 (要么我們剛剛用相應的行關閉了前一個塊sid:,要么我們現在知道當前的塊與前一個塊reference:相同sid:。)檢查空字串並不是真正必要的,因為我假設每一sid:行前面都有一行reference:
  • oldsid=$0;儲存目前sid:行以便在獲得下一行時進行比較。目前行尚未列印。
  • END { if (oldsid != "") print oldsid; }最後列印最後儲存的sid:行(如果有)。 (如果輸入檔案為空,則不會在此列印空行。)

該腳本基於以下假設:

  • everyreference:後面跟著一個sid:
  • 具有同一行的所有對reference:和都相互跟隨sid:sid:

相關內容