您的位置:首页 > 运维架构 > Shell

【经验总结】Bash处理文本总结

2011-05-11 09:10 225 查看
Bash处理文本总结

By 小左

    在做运维工作的时候, 经常会遇到一些统计需求,从业务侧的日志统计某个业务的运营数据, 不可避免的要对日志进行文本处理
    小左总结了自己在工作常使用的文本处理方法, 分享给大家。
    1. 求两个文件的交集,并集
        交集: 假设有a.txt 和b.txt,每个文件都有用户的手机号,每个手机号各占一行,找出a.txt和b.txt中都有的手机号
        法1. awk 'NR==FNR{ arr[$0]="x" } NR>FNR{ if(arr[$0]!=""){ print $0 } }' a.txt b.txt
        法2. 使用grep的-f FILE选项。 缺点: 当FILE里的记录数稍微多一点, 检索的速度就变的相当的慢.

        并集: 假设有两个文件a.txt和b.txt, 其中a.txt中有两列, 第一列为手机号, 第二列为该手机今天上行的短信条数; b.txt中也有两列,第一列为为手机号, 第二列为该手机号今天的消费数,要求把a,b两文件合并成一个,输出“手机号 上行短信数 消费数”这样一个文本, 某列的数据为空则补零
        法1. awk 'NR==FNR{ a[$1]=$2 } NR>FNR{ if(a[$1] != ""){ print $1, a[$1], $2 }else{ print $1, 0, $2 }; a[$1]="x" } END{ for(i in a){ if(a[i]!="x"){ print i, a[i], 0} } }' a.txt b.txt
         法2. 使用join。 缺点: 一是需要对join的对象文件先做好排序, 二是join的对象文件只支持两个域,三是join支持的key不能包含空格, 而awk的数组下标字符串可以包含空格,从而法1可以支持多个域作为key来合并两个文件
        NR ( Number of Record) 经过awk处理的总记录数
        FNR ( File Number of Recored ) awk处理的当前文件的记录数, 想上面的, 当awk在读b.txt的时候, FNR重新变成0, NR则在a.txt的记录数上继续增加
    2. 还需要unix2dos/dos2unix么?
        并不是不需要unix2dos/dos2unix, 问题是unix2dos这个工具在我们大多数linux服务器上根本没有。 xx: bin, 你给偶的文件怎么格式乱乱的啊. 偶bin总不能说, xx你拿ue做一下unix到dos文本的格式转换吧。其实弄清楚windows与unix文本格式的差异, 及awk处理文本的方式,用一条很简单的命令就
可以实现unix2dos的功能了。 赶快试试吧:)
        awk '{ print $0"/r" }' ur_file > ur_file.txt
        dos2unix这个工具偶们的服务器上一般是有的, 但是万一要是木有呢? 不能站着干着急, 把windows格式文本里的'/r'这个字符删掉就OK,试试这个吧:
        tr -d '/r' < dosfile.txt > unixfile.txt
    3. sed的域
        xx: bin,快帮我从日志里统计一下昨天每个用户的消费数
        bin: re啊, yyGG的日志里怎么没有记录消费数这个域啊, 不过记录的短信内容都里“本条mm元”的字样。 hoho, 这不好办了吗,赶快使用sed来提取出mm吧。
        $ head -n 1 down_20090201.log
        [00:00:00] |0000000000|0|172.0.0.1|Cmd|Fee_Pass_Succ|10660000|15999999999||gdgmcc|gdgmcc|755||1|WX|NORMAL|-NZZZZZ2|JPQQQ|2|200|0|10660000||1|3030303030303137313136333433373234323639|0000832f08018000|1|欢迎使用中国象棋, 本条2元(不含通信费),询95100000|
        $ awk -F'|' '{ print $1"|"$3"|"$8"|"$28 }' down_20090201.log | sed -n 's/.*|/(.*/)|/(.*/)|.*本条/(.*/)元.*//2 /3/p'
        看看是不是把手机号和用户的消费数打印出来啦~~~

    4. 像sql那样group by / order by
        已经在日志里提取出了每条记录的手机号和消费数啦, 但是xx需要的是每个用户的消费总数哦, 就想sql里的select sum(xx) .. group by yy 表急, “瑞士军刀”awk又该亮相啦~~
        假设文件a.txt里有用户的手机号和消费数两列, 求每个手机号消费总数: awk '{ sum[$1]+=$2; } END{ for(i in sum){ print i, sum[i]} }' a.txt
        有时候,排序是避免不了的, 而且是针对多列排序... 一昏再昏, 而且是对某一列做顺序, 对另外一列做逆序... 就像sql里的select * from xx order by date desc, name
        有一个文本文件, 第一列是日期格式为'YYYYMMDD', 第二列是文件名, 我想首先对第二列按字母顺序排序,然后在        这个基础上对第一列逆序排序。
        类似于sql里的select date, filename from t_name order by filename, date desc;
        文件如下:
            20090105 abc.txt
            20090105 xyz.txt
            20090105 follow.txt
            20090113 follow.txt
            20090112 abc.txt

        经过sort之后, 文件变成
            20090112 abc.txt
            20090105 abc.txt
            20090113 follow.txt
            20090105 follow.txt
            20090105 xyz.txt
        答案: sort -k2,2 -k1,1nr ur_file

本文原创自无线技术运营空间: http://wireless.qzone.qq.comhttp://blog.csdn.net/wireless_tech (专注无线技术运营——无线技术(操作系统/数据库/WEB前端/负载均衡/系统容灾/系统安全/短信接入/WAP接入/3G等)、无线业务运营、无线开放平台、统计分析(用户行为分析/数据挖掘)、CP合作,联系我们:1780551083@qq.com)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: