《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 : -k 3nr,3 -k 2,2 CARGO.db  #以第3个域数字逆排序,如果第3个域相同,以第2个域再排序

# 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

5.4 cut命令

cut命令用于从标准输入或文本文件中按域或字符提取文本

cut -c/-f/-d input

-c:指定提取的第几个字符或字符范围

-f:指定其他的第几个于或域范围

-d:改变域分隔符

# cut -c3 input.txt   -> 提取每行第三个字符

# cut -c1-5 input.txt   -> 提取每行第1至第5个字符

# cut -c1,5 input.txt   -> 提取每行第1和第5个字符

# cut -d: -f1,4 input.txt  -> 以:作为分隔符提取第1和第4个域

# cut -d: -f1-3 input.txt  -> 以:作为分隔符提取第1至第3域

5.5 paste命令

paste用于将文本文件或标准输出中的内容粘贴到新的文件中去,它可以将来自不同文件的数据粘贴在一起,输出到标准输出中去,或重定向到一个新的文件。

# paste [option] file1 file2

-d:默认域分隔符是空格或Tab键,设置新的域分隔符

-s:将每个文件粘贴成一行

-:从标准输入中读取数据

# paste -d@ FILE1 FILE2   -> 每一行FILE1输入在前,FILE2数据在后,然后用@分割

注:paste的-d跟其他sort、join、cut命令是不一样的,仅仅是为了设置输出文件的格式而已。

5.6 split命令

split命令用于将大文件切割成小文件,split命令可以按照文件的行数、字节数切割文件,并能在输出的多个小文件中自动加上编号。

# split [option] bigfile smallfile

- 或 -l:用于指定切割成的小文件的行数

-b:指定切割成的小文件的字节数

-C:与-b类似,也是指定字节数,但是切割时尽量维持每行的完整性

# split -2 big.txt small.txt

split命令切割成的小文件最多只能有1000行

# split -b100 big.txt small.txt

# split -C100 big.txt small.txt

--------------------------常见命令------------------------------

# 文件夹下面查找最大的文件:

# find -type f ! -path '*/.svn/*' -exec stat -c "%s %n" {} \;|sort -nr|head -10

相关推荐