《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