Chinaunix

标题: 求一个分组的shell脚本,高手进来帮个忙 [打印本页]

作者: fengfeng919    时间: 2014-01-15 14:38
标题: 求一个分组的shell脚本,高手进来帮个忙
本帖最后由 fengfeng919 于 2014-01-15 15:08 编辑

源文件:
cap_friend_goods_20131011
cap_friend_goods_20141011
cap_friend_goods_20150211
cap_friend_goods_20150911
cap_friend_goods_20151012
cap_friend_goods_20161111
cap_trade_ask_syn_20130119
cap_trade_ask_syn_20140120
cap_trade_ask_syn_20150919
cap_goods_20130429
cap_goods_20141229
cap_goods_20141108
cap_goods_20150814
cap_log_goods_20121011
cap_log_goods_20121108
cap_log_goods_20131011
cap_log_goods_20141207
cap_log_goods_20141012
cap_log_goods_20151011

脚本处理后结果:
cap_friend_goods_20131011
cap_friend_goods_20161111
----------------
cap_trade_ask_syn_20130119
cap_trade_ask_syn_20150919
----------------
cap_goods_20130429
cap_goods_20150814
----------------
cap_log_goods_20121011
cap_log_goods_20151011

要求:想得到按照日期前面的前缀分组,然后取得每组里面最早时间和最晚时间的两条,这个脚本应用怎么写?

作者: fengfeng919    时间: 2014-01-15 14:38
自己先顶一下,,,
作者: yestreenstars    时间: 2014-01-15 15:00
cap_log_goods_20121011
cap_log_goods_20120908
cap_log_goods_20131011
cap_log_goods_20141207
cap_log_goods_20141012
cap_log_goods_20151011

上面最小的是cap_log_goods_20120908,为什么下面却是cap_log_goods_20121011?
cap_log_goods_20121011
cap_log_goods_20151011

作者: fengfeng919    时间: 2014-01-15 15:09
抱歉,因为为了好理解,我手动编辑的时候写出入了,我改过来了,有脚本可以做到吗,谢谢。回复 3# yestreenstars


   
作者: ly5066113    时间: 2014-01-15 15:11
回复 1# fengfeng919


try:
  1. awk -F _ '{v=$0;NF--;if(!a[$0]++){print s"\n----------------\n"v}}{s=v}END{print s}' file
复制代码

作者: yestreenstars    时间: 2014-01-15 15:21
本帖最后由 yestreenstars 于 2014-01-15 15:23 编辑

如果对原始顺序无要求的话:
  1. $ sort i | awk -F_ '!b;{a=$0;NF--}b&&b!=$0{print c"\n----------------\n"a}{b=$0;c=a}END{print c}'
  2. cap_friend_goods_20131011
  3. cap_friend_goods_20161111
  4. ----------------
  5. cap_goods_20130429
  6. cap_goods_20150814
  7. ----------------
  8. cap_log_goods_20121011
  9. cap_log_goods_20151011
  10. ----------------
  11. cap_trade_ask_syn_20130119
  12. cap_trade_ask_syn_20150919
复制代码

作者: yestreenstars    时间: 2014-01-15 15:24
你的数据是排好序的吗?注意高亮部分:
cap_friend_goods_20131011
cap_friend_goods_20141011
cap_friend_goods_20150211
cap_friend_goods_20150911
cap_friend_goods_20151012
cap_friend_goods_20161111
cap_trade_ask_syn_20130119
cap_trade_ask_syn_20140120
cap_trade_ask_syn_20150919
cap_goods_20130429
cap_goods_20141229
cap_goods_20141108

cap_goods_20150814
cap_log_goods_20121011
cap_log_goods_20121108
cap_log_goods_20131011
cap_log_goods_20141207
cap_log_goods_20141012
cap_log_goods_20151011

作者: yestreenstars    时间: 2014-01-15 15:25
如果是已经排好序的,就直接用:
  1. awk -F_ '!b;{a=$0;NF--}b&&b!=$0{print c"\n----------------\n"a}{b=$0;c=a}END{print c}'
复制代码

作者: ly5066113    时间: 2014-01-15 16:49
sed
  1. sed -r ':a;N;$!ba;s/([^\n]*)(_.{8})\n.*(\n\1_.{8})/----------------\n\1\2\3/g' file
复制代码

作者: fengfeng919    时间: 2014-01-15 17:11
回复 5# ly5066113

感谢tim大师,可以用,但是有个问题,例如有下面的情况:
cap_friend_goods_20131011
cap_friend_goods_20141011
cap_friend_goods_20150211
cap_friend_goods_20150911
cap_friend_goods_20151012
cap_friend_goods_history

然后就悲剧了,会把这个组的最后一个判断为history,这有点蛋疼,能改一下吗,其实我想要的是cap_friend_goods_20151012的?


   
作者: fengfeng919    时间: 2014-01-15 17:21
回复 8# yestreenstars
因为是数据库里出来的列表,所以默认是顺序的,但是例如
cap_friend_goods_20131011
cap_friend_goods_20141011
cap_friend_goods_20150211
cap_friend_goods_20150911
cap_friend_goods_20151012
cap_friend_goods_history
会把
cap_friend_goods_history
作为这个组的最后一项

   
作者: ly5066113    时间: 2014-01-15 17:31
回复 10# fengfeng919


稍作修改即可:
  1. awk -F _ '{v=$0;NF--;if(!a[$0]++){print s"\n----------------\n"v}}v~/[0-9]$/{s=v}END{print s}' file
复制代码

作者: fengfeng919    时间: 2014-01-15 17:33
回复 12# ly5066113

感谢tim大哥,我要好好的理解一下,晕着呢,好好


   
作者: fengfeng919    时间: 2014-01-16 11:38
回复 12# ly5066113

tim哥,感谢昨天的帮忙,目前内容有个小变化,,就是前缀是一样,但是有年月格式还同时有年月日的时间格式,如下:
cap_goods_201111
cap_goods_201112
cap_goods_201201
cap_goods_20130429
cap_goods_20141229
cap_goods_20150814

希望正则之后的结果为:

cap_goods_201111
cap_goods_201201
cap_goods_20130429
cap_goods_20150814
作者: yestreenstars    时间: 2014-01-16 12:22
猜一下:
  1. $ awk -F_ '!t;t&&length(t)!=length($NF){print s"\n"$0}{s=$0;t=$NF}END{print s}' i
  2. cap_goods_201111
  3. cap_goods_201201
  4. cap_goods_20130429
  5. cap_goods_20150814
复制代码

作者: fengfeng919    时间: 2014-01-16 12:45
回复 15# yestreenstars

虔诚感谢,貌似可以用,我再测试一下,可以解释依稀,我理解了一下,没看懂!


   
作者: yestreenstars    时间: 2014-01-16 13:39
回复 16# fengfeng919
我把它分成几步来讲解吧。
  1. !t 在t未初始化时打印当前行的内容
  2. t&&length(t)!=length($NF){print s"\n"$0} 当t的值存在且t的长度不等于当前行的最后一个字段的长度时,打印上一行的内容和当前行的内容
  3. {s=$0;t=$NF} 将当前行的内容赋值给s,最后一个字段赋值给t
  4. END{print s} 打印最后一行的内容
复制代码


   
作者: elu_ligao    时间: 2014-01-18 23:52
  1. awk -F_ '{s=$0;nf=$NF;sub(/[0-9]+$/,"",s);print nf,s,$0}' file | sort -k2,2 -k1n | awk '{print $3}' | awk -F_ -v sep="-----------" '{s=$0;lnf=length($NF);--NF;}s~/[0-9]$/{if(t!=$0||len!=lnf){print l?l"\n"sep"\n"s:s}t=$0;l=s;len=lnf}END{if(s~/[0-9]$/)print s}'
复制代码
回复 14# fengfeng919


   
作者: fengfeng919    时间: 2014-01-21 11:21
回复 12# ly5066113


tim哥,感谢前几天的帮忙,你改进的那个『awk -F_ '!t;t&&length(t)!=length($NF){print s"\n"$0}{s=$0;t=$NF}END{print s}'』可以正常使用,但是有个小变化,就是前缀是一样,但是同时有年月格式还有年月日的时间格式,如下:
cap_goods_201111
cap_goods_201112
cap_goods_201204
cap_goods_20130429
cap_goods_20141229
cap_goods_20150814

希望正则之后的结果为:

cap_goods_201111
cap_goods_201204
cap_goods_20130429
cap_goods_20150814


   
作者: ly5066113    时间: 2014-01-21 14:58
回复 19# fengfeng919


你的这个代码是 yestreenstars 的

作者: fengfeng919    时间: 2014-01-21 15:29
回复 20# ly5066113


  不好意思,哈哈

应该是这个:awk -F _ '{v=$0;NF--;if(!a[$0]++){print s"\n----------------\n"v}}v~/[0-9]$/{s=v}END{print s}'

怎么修改一下呢?


   
作者: ly5066113    时间: 2014-01-21 16:10
回复 21# fengfeng919


try:
  1. awk -F _ '!/[0-9]$/{next}{v=$0;l=length($NF);NF--;if(!a[$0,l]++){print s"\n"v}}{s=v}END{print s}' file
复制代码

作者: fengfeng919    时间: 2014-01-22 10:51
回复 22# ly5066113

谢谢tim哥,我测试去,昨天晚上又悲剧了,表又坏了,所以没上来回复。


   




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2