用几条shell命令快速去重10G数据

来源:互联网 发布:包头广电网络营业厅 编辑:程序博客网 时间:2024/05/16 01:42
试想一下,如果有10G数据,或者更多;怎么才能够快速地去重呢?你会说将数据导入到数据库(mysql等)进行去重,或者用java写个程序进行去重,或者用Hadoop进行处理。如果是大量的数据要写入数据库也不是一件容易的事情,首先你需要开发一个程序将数据写入数据库,然后再用数据库的select distinct或者group by进行去重。如果是一次性的工作,这种方式显得就比较笨拙了。那么有没有更好的办法呢?下面记录一下我是怎么从10G数据里面迅速去重的。这里采用shell脚本的方式进行处理。如果您对shell脚本不熟悉,可以参考之前的文章我常用的那些linux命令,里面介绍了我常用的一些linux命令。也可以查看本博客的linux分类http://www.cnblogs.com/rwxwsblog/category/687866.html,基本上就是里面说到的一些知识点。好了,入正题。   一、说明:   1、这10G数据分布在七八个文件中   2、文件编码格式为gb2312   3、数据格式: 复制代码 "ID","已采","已发","内容","PageUrl" "1","1","1","====================会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||====================会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||====================会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||====================会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||","http://www.xxx.com/" "1","1","1","====================会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||====================会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||====================会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||====================会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||","http://www.xxx.com/" "1","1","1","====================会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||====================会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||====================会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||====================会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||","http://www.xxx.com/" 复制代码     数据格式说明: 上面是3行数据每行都是5个field 每个field间用“,”隔开而需要的内容在第4个field(也就是内容这个field)内容field间会员用“====================”隔开  要达到的效果:将会员信息提取出来并去重   二、实现思路和测试:   1、由于文件编码是gb2312编码,所以第一步是将文件编码转成utf-8编码 iconv -c -f gb2312 -t utf-8 test.txt > test2.txt   这里我们用linux系统自带的iconv命令进行转换,-c的意思是将无法识别的字符直接忽略掉   2、获取会员信息,由于是第4个field,因而我们只需要获取第四个field即可,这里采用awk命令获取 awk 'BEGIN{ FS=",";}{ print $4 }' test2.txt > test_menber.txt   awk指定分隔符的方法为FS=",",运行后的结果如下 复制代码 vi test_menber.txt "内容" "====================会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||====================会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||====================会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||====================会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||" "====================会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||====================会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||====================会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||====================会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||" "====================会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||====================会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||====================会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||====================会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||" 复制代码  这里已经获取到了会员的信息;但是一行有多个会员的信息,而个数又是不固定的。因此下面是想办法一行显示一个会员   3、一行显示一个会员   由于会员信息间通过“====================”分割,要实现一行显示一个会员只需要将“====================”替换成换行即可。 sed -i "s/====================/\n/g" test_menber.txt   查看test_menber.txt的内容 复制代码 vi test_menber.txt 1 "内容" 2 " 3 会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 ||| 4 会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 ||| 5 会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 ||| 6 会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||" 7 " 8 会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 ||| 9 会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 ||| 10 会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 ||| 11 会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||" 12 " 13 会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 ||| 14 会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 ||| 15 会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 ||| 16 会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||" 复制代码     4、替换掉其他字符“"”、空行和“|||” #将“"”替换成空字符串 sed -i "s/\"//g" test_menber.txt #删除空行 sed -i '/^$/d' test_menber.txt #将分隔符|||换成@ sed -i "s/|||/@/g" test_menber.txt      5、根据会员名去重 sort -t $"@" -k 1,1 -su test_menber.txt >test_uniq.txt   -t可以指定分隔符,-k指定排序的field, -su表示稳定排序并去重   查看结果 [root@bogon yichen]# more test_uniq.txt 会员名:鬼脚七@@@@@@会员等级:军长第5年@姓名:张三 @ 内容  思路和测试完成了,但是文件比较多,一个个文件去处理也比较麻烦。因而写个脚本去处理即可   三、脚本批量处理   1、转换文件编码 复制代码 [root@bogon yichen]# vi iconv_shell.sh #!/bin/sh if [ "$#" != "2" ]; then echo "Usage: `basename $0` dir filter" exit fi echo $1 for file in `find $1 -name "$2"`; do echo "$file" iconv -c -f gb2312 -t utf8 $file > ${file}_utf8 复制代码  调用./iconv_shell.sh 目录 文件通配符,例如: ./iconv_shell.sh ./ "*txt"   此时生成的文件后缀为:.txt_utf8   2、提取会员信息 复制代码 vi awk_filler.sh #!/bin/sh if [ "$#" != "2" ]; then echo "Usage: `basename $0` dir filter" exit fi for file in `find $1 -name "$2"`; do echo "$file" awk 'BEGIN{ FS=",";}{ print $4 }' $file > ${file}_menber done 复制代码  调用 ./awk_filler.sh ./ "*.txt_utf8"   此时生成的文件后缀为:.txt_utf8_menber   3、替换“====================”、“"”、“|||”和换行 复制代码 vi sed_shell.sh #!/bin/sh if [ "$#" != "2" ]; then echo "Usage: `basename $0` dir filter" exit fi for file in `find $1 -name "$2"`; do echo "$file" sed -i "s/====================/\n/g; s/\"//g; /^$/d; s/|||/@/g" $file done for file in `find $1 -name "$2"`; do echo "$file" sed -i "/^$/d" $file done 复制代码  sed支持多表达式:sed "表达式1;表达式2" filename,注意表达式之间用“;”号隔开。   调用: sh ./sed_shell.sh ./ "*.txt_utf8_menber"   替换后的文件后缀仍为txt_utf8_menber   4、去重 复制代码 vi uniq_shell.sh #!/bin/sh if [ "$#" != "2" ]; then echo "Usage: `basename $0` dir filter" exit fi for file in `find $1 -name "$2"`; do echo "$file" sort -t $"@" -k 1,1 -su ${file} >${file}_uniq done 复制代码  调用: sh ./uniq_shell.sh ./ "*.txt_utf8_menber"   最后生成去重后的文件后缀为txt_utf8_menber_uniq   其实也可以放在一个shell脚本里面完成,这里就不再阐述了。想想看10G的文件用几个简单的命令就完成了去重,可见linux的强大。所以说学几个简单的linux命令还是很有必要的,这样可以大大地降低你的工作量,提高工作的效率。这是我觉得相对较快的处理方式,如果您有更好的处理方式不妨告诉我。 ---------------------------------------------------------------------------------我是分割线-------------------------------------------------------------------------- to be a better me, talk is cheap show me the code 版权所有,转载请注明原文链接。 文中有不妥或者错误的地方还望指出,以免误人子弟。如果觉得本文对你有所帮助不妨【推荐】一下!如果你有更好的建议,可以给我留言讨论,共同进步! 再次感谢您耐心的读完本篇文章。 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------
0 0
原创粉丝点击