我想删除每个具有非唯一ID的块,除了具有最新日期的ID。
我希望这些例子能够为自己说话。任何awk和/或sed解决方案都将不胜感激!
原始档案:
<BLOCK>
ID=1000
Text
Text
DATE=20160101
Text
</BLOCK>
<BLOCK>
Text
Text
ID=2000
DATE=20140101
Text
Text
</BLOCK>
<BLOCK>
ID=1000
DATE=20100101
Text
</BLOCK>
<BLOCK>
Text
ID=3000
Text
Text
DATE=20160101
Text
</BLOCK>
<BLOCK>
Text
Text
ID=2000
Text
DATE=20151231
</BLOCK>
结果应如下所示:
<BLOCK>
ID=1000
Text
Text
DATE=20160101
Text
</BLOCK>
<BLOCK>
Text
ID=3000
Text
Text
DATE=20160101
Text
</BLOCK>
<BLOCK>
Text
Text
ID=2000
Text
DATE=20151231
</BLOCK>
感谢您的帮助!
答案 0 :(得分:1)
使用gnu awk你可以这样做:
awk -v RS= '{
dt = gensub(/.*\nDATE=([0-9]+).*/, "\\1", "1")
key = gensub(/.*\n(ID=[0-9]+).*/, "\\1", "1")
if (dt > c[key]) {
c[key] = dt
arr[key]=$0
}
}
END {
for (i in arr)
print arr[i] ORS
}' file
<BLOCK>
ID=1000
Text
Text
DATE=20160101
Text
</BLOCK>
<BLOCK>
Text
Text
ID=2000
Text
DATE=20151231
</BLOCK>
<BLOCK>
Text
ID=3000
Text
Text
DATE=20160101
Text
</BLOCK>
答案 1 :(得分:0)
这个awk cmd完成给定输入的工作:
awk 'BEGIN{ORS=RS="</BLOCK>\n"}
{for(i=1;i<=NF;i++){
if($i~/^ID=/){
if(a[$i])next;else{a[$i]=1;print}}}}' file
输出:
<BLOCK>
ID=1000
Text
Text
DATE=20160101
Text
</BLOCK>
<BLOCK>
Text
Text
ID=2000
DATE=20140101
Text
Text
</BLOCK>
<BLOCK>
Text
ID=3000
Text
Text
DATE=20160101
Text
</BLOCK>
答案 2 :(得分:0)
使用gnu awk 4.0多行记录和PROCINFO [&#34; sorted_in&#34;] - 保留每个ID的最新记录 - 保留输入中记录的相对顺序
awk '
BEGIN{ ORS=RS="\n</BLOCK>" }
{
for(i=1; i <=NF; ++i) {
if($i ~ /^ID=[0-9]+/) id=$i
else if($i ~ /^DATE=[0-9]{8}/) date=$i
}
if(id in recs && date <= maxdate[id]) next
recs[id]=$0; maxdate[id]=date; order[id]=NR
}
END {
PROCINFO["sorted_in"]="@val_num_asc"
for(id in order) print recs[id]
}
'
输出
<BLOCK>
ID=1000
Text
Text
DATE=20160101
Text
</BLOCK>
<BLOCK>
Text
ID=3000
Text
Text
DATE=20160101
Text
</BLOCK>
<BLOCK>
Text
Text
ID=2000
Text
DATE=20151231
</BLOCK>
答案 3 :(得分:0)
改变输入要求的解决方案 - OP表示输入ID和DATE行是这样的 - 检查更新记录现在使用完整时间戳而不仅仅是日期
<ID V="1000"/>
<DATE V="20160101 00:00:00"/>
这个awk 4.0解决方案还使用PROCINFO [“sorted_in”]
来表达输入中记录的相对顺序awk -F'\n' '
BEGIN{
ORS=RS="\n</BLOCK>"
}
{
id=date=""
for(i=1; i <=NF; ++i) {
if(id && date) break
if($i ~ /<ID V=\"[0-9]+\"\/>/)
id=$i
else if($i ~ /<DATE V=\"[0-9]{8} [0-9]{2}:[0-9]{2}:[0-9]{2}\"\/>/)
date=$i
}
if(id in recs && date <= newest[id]) next
recs[id]=$0; newest[id]=date; order[id]=NR
}
END {
PROCINFO["sorted_in"]="@val_num_asc"
for(id in order) print recs[id]
}
'
针对相同ID和日期的一些不同时间的示例输入
<BLOCK>
<ID V="1000"/>
Text
Text
<DATE V="20160101 00:00:00"/>
Text
</BLOCK>
<BLOCK>
Text
Text
<ID V="2000"/>
<DATE V="20140101 00:00:00"/>
Text
Text
</BLOCK>
<BLOCK>
<ID V="1000"/>
<DATE V="20100101 00:00:00"/>
Text
</BLOCK>
<BLOCK>
Text
<ID V="3000"/>
Text
Text
<DATE V="20160101 00:00:00"/>
Text
</BLOCK>
<BLOCK>
Text
<ID V="4000"/>
Text
Text
<DATE V="20130101 11:00:00"/>
Text
</BLOCK>
<BLOCK>
Text
Text
<ID V="2000"/>
Text
<DATE V="20151231 00:00:00"/>
</BLOCK>
<BLOCK>
Text
<ID V="4000"/>
Text
Text
<DATE V="20130101 13:00:00"/>
Text
</BLOCK>
<BLOCK>
Text
<ID V="4000"/>
Text
Text
<DATE V="20130101 07:00:00"/>
Text
</BLOCK>
输出
<BLOCK>
<ID V="1000"/>
Text
Text
<DATE V="20160101 00:00:00"/>
Text
</BLOCK>
<BLOCK>
Text
<ID V="3000"/>
Text
Text
<DATE V="20160101 00:00:00"/>
Text
</BLOCK>
<BLOCK>
Text
Text
<ID V="2000"/>
Text
<DATE V="20151231 00:00:00"/>
</BLOCK>
<BLOCK>
Text
<ID V="4000"/>
Text
Text
<DATE V="20130101 13:00:00"/>
Text
</BLOCK>
答案 4 :(得分:0)
这适用于任何系统上的任何awk:
$ cat tst.awk
BEGIN { RS=""; ORS="\n\n" }
{
id = date = $0
gsub(/.*\nID=|\n.*/,"",id)
gsub(/.*\nDATE=|\n.*/,"",date)
}
date > dates[id] {
dates[id] = date
recs[id] = $0
}
END {
for (id in recs) {
print recs[id]
}
}
$ awk -f tst.awk file
<BLOCK>
ID=1000
Text
Text
DATE=20160101
Text
</BLOCK>
<BLOCK>
Text
Text
ID=2000
Text
DATE=20151231
</BLOCK>
<BLOCK>
Text
ID=3000
Text
Text
DATE=20160101
Text
</BLOCK>
你不能解释输出顺序应该是什么,而且你的例子并不明显,所以我假设你不在乎,所以上面输出的记录是&#34;随机& #34; (实际上是哈希)顺序。