从文件中提取并重新排列

从文件中提取并重新排列

我有一个文件,我想提取并重新排列某些数据,旧文件包含原始数据,该文件是输入

参考: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:

相关内容