试想一下,如果有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- 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 

       "内容"
"
会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||
会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||
会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||
会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||"
"
会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||
会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||
会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||
会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||"
"
会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||
会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||
会员名:鬼脚七||||||||||||||||||会员等级:军长第5年|||姓名:张三 |||
会员名:鬼脚七||||||||||||||||||会员等级:军长第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 , -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 [ "$#" != "" ]; then
echo "Usage: `basename $0` dir filter"
exit
fi
echo $
for file in `find $ -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 [ "$#" != "" ]; then
echo "Usage: `basename $0` dir filter"
exit
fi
for file in `find $ -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 [ "$#" != "" ]; then
echo "Usage: `basename $0` dir filter"
exit
fi
for file in `find $ -name "$2"`; do
echo "$file"
sed -i "s/====================/\n/g; s/\"//g; /^$/d; s/|||/@/g" $file
done for file in `find $ -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 [ "$#" != "" ]; then
echo "Usage: `basename $0` dir filter"
exit
fi
for file in `find $ -name "$2"`; do
echo "$file"
sort -t $"@" -k , -su ${file} >${file}_uniq
done

  调用:

sh ./uniq_shell.sh ./ "*.txt_utf8_menber"

  最后生成去重后的文件后缀为txt_utf8_menber_uniq

  其实也可以放在一个shell脚本里面完成,这里就不再阐述了。想想看10G的文件用几个简单的命令就完成了去重,可见linux的强大。所以说学几个简单的linux命令还是很有必要的,这样可以大大地降低你的工作量,提高工作的效率。这是我觉得相对较快的处理方式,如果您有更好的处理方式不妨告诉我。

用几条shell命令快速去重10G数据的更多相关文章

  1. java ssh远程服务器并执行多条shell命令

    java ssh远程服务器并执行多条命令 import java.io.BufferedReader; import java.io.IOException; import java.io.Input ...

  2. 一条shell命令让多台Linux服务器执行

    1.环境 局域网环境有3台Linux服务器,配置host文件 [root@master1 ~]# vim /etc/hosts 192.168.8.201 master1 192.168.8.202 ...

  3. 几条shell命令

    windows: route add 158.0.0.0 mask 255.0.0.0 158.137.38.1 metric 3 linux: netstat -apn  查看所有端口使用,可查看端 ...

  4. Oracle中用exp/imp命令快速导入导出数据

    from: http://blog.csdn.net/wangchunyu11155/article/details/53635602 [用 exp 数 据 导 出]: 1 将数据库TEST完全导出, ...

  5. 使用jq工具在Shell命令行处理JSON数据

    由于近期要处理一些 JSON 数据格式.一大早经过一番搜索后,终于找到了 jq 这个非常棒的工具.jq 同意你直接在命令行下对 JSON 进行操作,包含分片.过滤.转换等等. 首先在mac下安装jq. ...

  6. 如何使用shell脚本快速排序和去重文件数据

    前面写过一篇通过shell脚本去重10G数据的文章,见<用几条shell命令快速去重10G数据>.然而今天又碰到另外一个业务,业务复杂度比上次的单纯去重要复杂很多.找了很久没有找到相应的办 ...

  7. adb shell 命令

    adb 概述 SDK的Tools文件夹下包含着Android模拟器操作的重要命令adb,adb的全称为(Android Debug Bridge就是调试桥的作用.通过adb我们可以在Eclipse中方 ...

  8. android: shell 命令

    adb是Android重要工具之一,以提供强大的特性,例如复制文件到设备或从设备复制文件.可以使用Android Shell命令行参数连接到手机本身,并发送基本的 shell 命令. 进入命令行,使用 ...

  9. 常用shell命令实战

    #!/bin/sh ################### #### 环境变量 ### ################### #主程序目录 #APP_HOME=/apps/svr/apache-to ...

随机推荐

  1. WPF小知识,MessageBox的多种用法

    我们在程序中经常会用到MessageBox. 现将其常见用法总结如下: 1.MessageBox.Show("Hello~~~~"); 最简单的,只显示提示信息. 2.Messag ...

  2. DVR分布式路由

    1. 背景 没有使用DVR的场景: 从图中可以明显看到东西向和南北向的流量会集中到网络节点,这会使网络节点成为瓶颈. 如果启用DVR,如下图: 对于东西向的流量, 流量会直接在计算节点之间传递. 对于 ...

  3. 【BZOJ 3674】可持久化并查集加强版&【BZOJ 3673】可持久化并查集 by zky 用可持久化线段树破之

    最后还是去掉异或顺手A了3673,,, 并查集其实就是fa数组,我们只需要维护这个fa数组,用可持久化线段树就行啦 1:判断是否属于同一集合,我加了路径压缩. 2:直接把跟的值指向root[k]的值破 ...

  4. 总结css之内联图片的优缺点

    会不会有这样一种感觉?IT技术开发知识面很广也很深,总会有你不懂得问题出现.一个接着一个新的问题,一个接着一个新的挑战. 今天,解读[内联图片],什么是内联图片,使用内联图片的优缺点是什么?这个问题是 ...

  5. Android 设计模式 之 单例模式

    http://blog.csdn.net/fangchongbory/article/details/7734199   目录(?)[+] 单例模式常见情景 首先实现1中的单例模式A 实现2中单例模式 ...

  6. linux内存回收 内核参数

    ss -atu| awk '/^tcp/{++S[$2]} END {for(a in S) print a,S[a]}' ps up pid (RSS:实际内存大小,长驻内存) ps o pid,c ...

  7. zabbix表结构

    zabbix数据库表结构的重要性 想理解zabbix的前端代码.做深入的二次开发,甚至的调优,那就不能不了解数据库的表结构了. 我们这里采用的zabbix1.8.mysql,所以简单的说下我们mysq ...

  8. 用多态来实现U盘,Mp3,移动硬盘和电脑的对接,读取写入数据。

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  9. std::thread join和detach区别

    thread detach, join 线程有两种状态,joinable或者detachable,pthread默认创建的线程是joinable的,也可以指定atrribute创建成一个detacha ...

  10. yii框架常用url地址

    调用YII框架中 jquery:Yii::app()->clientScript->registerCoreScript('jquery');        framework/web/j ...