日期:2014-05-16  浏览次数:20861 次

《Linux Shell》之四:文件的排序、合并和分割

Linux的文本处理命令,包含sort、uniq、join、cut、paste、split、tr、tar,这些命令能实现对文件记录排序、统计、合并、提取、粘贴、分割、过滤、压缩和解压缩等,它们与sed和awk一起构成了Linux文本处理的所有命令和工具。

?

5.1 sort命令

# sort [选项] [输入文件]

选项 意义
-c 测试文件是否已经排序
-k 指定排序的域
-m 合并两个已排序的文件
-n 根据数字大小进行排序
-o [输出文件] 将输出写到指定的文件,相当于将输出重定向到文件
-r

将排序结果逆向显示

-t 改变域分隔符(默认是空格)
-u 去除结果中的重复行

?

先建立一个CARGO.db的示例文件:

?

Thindpad:USA:14000:2009:X301
Thinkpad:HongKong:10000:2008:T400
Thinkpad:USA:8000:2007:X60
HP:China:5600:2010:DM3
HP:China:12000:2010:NE808
SumSung:Korea:5400:2009:Q308
IdeaPad:China:8000:2007:U450

# sort -t: CARGO.db ? #以默认方式对CARGO.db进行排序,注意-t跟:之间没有空格,也可以加空格

?

# sort -t : -k3 CARGO.db

注:-k3虽然是以第三个域来排序,但还是以默认的字符排序方法,不是数字,如果第三个域相同,那么再依次以第4个域、第5个域排序。

# sort -t : -k3n CARGO.db ?#以第3个域并且以数字顺序排序

# sort -t : -k3nr CARGO.db ?#以第3个域并且以数字顺序排序,逆向排序

# sort -t : -k3nr -o out CARGO.db ?#不输出到标准输出中,而是重定向到out文件中去

#?sort -t : -k3n -c CARGO.db ?#测试一下第3个域是否已经安装数字排好了序

# sort -t: -k3n -m CARGO.db CARGO.db2 ?#将两个已经按照第3域数字排好序的文件合并

?

5.1.2 sort和awk的联合使用

文本块的排序,一个文件中有很多相似的段落,每个段落记录一个人的姓名地址等,如果段落排序:

# cat PROFESSOR.db | awk -v RS="" '{gsub("\n","@");print}' | sort | awk -v ORS="\n\n" '{gsub("@","\n");print}'

?注:awk -v 用于定义一个变量供后面使用,可以覆盖系统变量

可以看出当RS为空时,awk会自动以多行来做为分割符。 上面的RS也可以为RS="\n\n"

?

5.2 uniq命令

选项 意义
-c 打印每行在文本中重复的次数
-d 只显示有重复的记录,每个重复记录只出现一次
-u 只显示没有重复的记录

注意uniq跟sort -u的区别,uniq的重复行必须是连在一起才会去算的,分开了就另外算一条记录了。

#!/bin/bash
# 统计一个文件中每个单词出现的次数

ARGS=1        #输入参数个数为1,就是一个文件名
E_BADARGS=55  #输入参数错误码
E_NOFILE=56   #输入文件不存在

# 参数个数不为1,返回错误码E_BADARGS
if [ $# -ne "$ARGS" ];then
        echo "Usage: 'basename $0' filename"
        exit $E_BADARGS
fi

# 输入的文件名不存在,返回错误码E_NOFILE
if [ ! -f "$1" ];then
        echo "File \"$1\" does not exists."
        exit $E_NOFILE
fi

# 以下是核心算法
# sed命令用于过滤句号、逗号、分号,当然可以继续加上需要过滤的符号
# sed命令第4个-e选项将单词间的空格转化为换行符
# sort对sed过滤结果排序,每行一个单词
# uniq -c输出重复行的次数,sort -nr 按照出现频率从大到小排序
sed -e 's/[\.\,\:\;\!]/ /g' -e 's/\s\+/ /g' -e 's/\s\+$//g' -e 's/ /\n/g' "$1" | sort | uniq -c | sort -nr

exit 0

?