我有一个文件,我想提取并重新排列某些数据,旧文件包含原始数据,该文件是输入
参考: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: