bash,sed,awk删除具有重复ID和块内较旧日期的文本块

时间:2016-08-29 15:34:30

标签: bash awk sed

我想删除每个具有非唯一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>

感谢您的帮助!

5 个答案:

答案 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; (实际上是哈希)顺序。