Shell(五):文件的排序、合并和分割
Linux文本处理命令是Shell编程中的常用命令,文本处理包含对文件记录的排序、文件的合并和分割等。
1、sort命令
sort命令是一种对文件排序的工具,sort命令将输入文件看做由多条记录组成的数据流,而记录由可变宽度的字段组成,以换行符作为定界符。
sort命令,可将记录分成多个域进行处理,默认的域分隔符是空格符,域分隔符可由用户指定其他符号。sort命令的基本格式为:
sort [选项] [输入文件]
sort命令选项及其意义:
选项 |
含义 |
-c |
测试文件是否已经排序 |
-k |
指定排序的域 |
-m |
合并两个已排序的文件 |
-n |
根据数字大小进行排序 |
-o [输出文件] |
将输出写到指定的文件,相当于将输出重定向到指定文件 |
-r |
将排序结果逆向显示 |
-t |
改变域分隔符 |
-u |
去除结果中的重复行 |
1.1、sort命令的基本用法
1.1.1、-t 选项
sort命令是分域对文件进行排序的,默认的域分隔符是空格符,-t选项可用于设置分隔符。
对/etc/passwd文件进行排序:
/etc/passwd文件用冒号分隔域的,sort命令对/etc/passwd文件进行排序,用 -t 选项指定域分隔符为冒号,-t 与 ":" 之间没有空格。sort命令默认根据第1域对数据记录进行排序,若第1域相同,再根据第2域排序。
当未指定 -t 时,分隔符是空格符,此时记录内开头与结尾的空格都将被忽略;当用 -t 选项改变分隔符时,空格符就有意义。
空格符:root:空格符
对于上面的数据记录,若不指定 -t 选项,该记录了只有一个域,为 :root:,记录前后的空格符都被忽略;若用 -t 选项指定冒号,这条记录就包含了三个域,第1和3域是空格符,第2域是:root:。
1.1.2、-k 选项
sort命令默认情况按第1域进行排序,也可按指定某个域进行排序,-k选项就是用于指定域的。
sort命令以 1 表示第1域、以2表示第2域。
上例根据第5域对 /etc/passwd 进行排序。命令利用 -k5 指定了第3域。
1.1.3、-n 选项
-n 选项可以指定根据数字大小进行排序,详情如下:
-n选项一般放在域号之后,-k3n就指定了以第3域排序,且不是按照第3与的字符串顺序排序,而是第3域的数字大小进行排序。
1.1.4、-r 选项
-r 选项用于将排序结果逆向显示。
-n 选项默认是按从小到大排序,-r 选项将结果逆向显示。
1.1.5、 -u 选项
-u 选项用于去除排除结果的重复行,若文件中有重复济洛路,可利用 -u 选项进行去重:
1.1.6、-o 选项
sort命令默认将排序后的结果输出到屏幕,若需要将结果保存到另一个文件中,可使用 -o 选项 加上文件名来完成。
将 /etc/passwd 按第3域的数值大小排序,并将排序结果存储到result.txt文件中,此时屏幕上不再显示任何信息。
-o 选项与 Shell 提供的I/O重定向功能一样。
1.1.7、-c 选项
-c 选项用于测试文件是否已经排好序:
测试result.txt是否按照默认方式排序,提示信息中包含了该文件中第1条未排序的记录。
测试result.txt文件是否按照第3域的数值大小排序,result.txt是按这种方式排好序的,Shell不提示任何信息。
1.1.8、-m 选项
-m 选项用于将两个排好序的文件合并合成一个排好序的文件,在文件合并前,必须已经排好序。-m 选项对未排序的文件合并没有意义。
1.2、sort和awk的联合使用
sort和awk都是分域处理文件的功能根据,结合起来可以有效的对文本块进行排序。
文本块是由多行记录组合而成的数据块,PROFESSOR.txt 如下:
J Luo
Southeast University
Nanjing, China
Y zhang
Victory University
Melbourne, Australia
D Hou
Beijing University
Beijing, China
B Liu
Shanghai Jiaotong University
Beijing, China
C Lin
University of Toronto
Toronto, Canada
PROFESSOR.txt中每个文件块记录了一位学者信息,由三行组成:第 1 行是姓名、第 2 行是学校名、第 3 行是学校所处的城市与国家。若需要根据姓名对文件块进行排序,结合 sort 和 awk 实现此功能。
实现此功能的语句,由4条命令3个管道符组成。
cat PROFESSOR.txt | awk -v RS="" '{ gsub("\n","@");print }' | sort | awk -v ORS="\n\n" '{ gsub("@", "\n"); print }'
cat命令将 PROFESSOR.txt 文件的内容作为第1条awk命令的输入数据;
awk命令将每个文件块合并到一行,并用gsub函数将换行符替换成@符号,如将第一个文件块变为 "J Luo @Southeast University @Nanjing, China@";
sort命令对这种格式的记录进行排序,默认以第1域排序,即按姓名的字母顺序,并将排序后的行作为第2条awk命令的输入数据;
第2条awk命令执行与第1条awk相反的功能,将并为一行的数据重新划分为文件块输出,实现方法是用gusb函数将@符号替换成换行符。
2、uniq命令
2.1、uniq与sort -u的区别
uniq命令用于去除文本文件的重复行,类似于 sort 命令的 -u 选项,两者区别如下:
sort -u命令,所有重复的记录都能被去掉;
uniq 命令,去除的重复行必须是连续重复出现的行,中间不能夹杂任何其他文件。
repeat.txt文件中的"this is a old content"记录先重复两次,隔开一行后,该行重复出现一次,用uniq命令去除repeat.txt文件重复行后,隔开的重复记录未被去除;而用sort -u 命令时,所有的重复记录了都被去掉。
2.2、uniq命令的选项
uniq命令有3个选项,详情如下:
选项
|
含义
|
-c
|
打印每行在文本中重复出现的次数
|
-d
|
只显示有重复的记录,每个重复记录只出现一次
|
-u
|
只显示没有重复的记录
|
uniq命令的-c选项打印每行在文本中重复出现的次数。
-d 选项用于显示有重复的记录,-u 选项显示没有重复的记录:
sort和uniq命令结合使用,统计一个文件内每种单词出现的次数,仙剑 count_word.sh,内容如下:
新建count_word.sh脚本,内容如下:
#!/bin/bash
# count_word: 该脚本统计文件中单词出现的次数
ARGS=1
E_BADARGS=55
E_NOFILE=56
# 判断执行节本是否带了输入参数,即需要统计的文件名
# 若未带输入参数,返回 55 错误码
if [ $# -ne "$ARGS" ]
then
echo "Usage: 'basename $0' filename"
exit $E_BADARGS
fi
# 判断当前目录下,输入的文件名是否存在
# 若文件不存在,则返回56错误码
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/\,//g' -e 's/\://g' -e 's/ /\n/g' "$1" | sort | uniq -c | sort -nr
exit 0
count_word.sh脚本运行时加上一个参数,该参数表示待统计单词出现频率的文件名。
第1个if/then结构,用于判断执行脚本时是否带了输入参数,若未带输入参数,返回55错误码;
第2个if/then结构,用于判断在当前目录下,输入的文件名是否存在,若该文件不存在,返回56错误码;
统计文件单词出现频率的命令,由sed、sort、uniq -c 和 sort -nr 四个命令组成,前面命令的输出作为后面命令的输入,sed命令的前三个-e选项 用于过滤句号、逗号、分号,可根据实际情况加上需要过滤的符号,sed命令的第4个 -e 选项将单词间的空格转化为换行符,将每个单词单独一行显示,便于sort命令排序。经过sed命令处理后,sort对行进行排序,同一个单词必定出现连续行,uniq -c输出重复行的次数,即该单词重复出现的次数。由于 uniq -c 的输出结果是"次数 单词"格式,sort -nr 对第 1 域(即单词出现的次数)进行排序,并倒置,使得出现次数多的单词排在最前面。
执行结果如下:
3、join命令
join命令用于实现两个文件中记录的连接操作,将两个文件中具有相同域的记录选择出来,再将这些记录所有的域放到一行。
新增 TEACHER.txt 文件,详情如下:
B Liu:Shanghai Jiaotong University:Shanghai:China
C Lin:University of Toronto:Toronto:Canada
D Hou:Beijing University:Beijing:China
Y Zhang:Victory University:Melbourne:Australia
新增 TEACHER_HOBBY.txt 文件,详情如下:
B Liu:Tea
C Lin:Song
J Cao:Pingpong
Q Cai:Shopping
Y Zhang:Photography
Z Wu:Chess
连接 TEACHER.txt 和 TEACHER_HOBBY.txt 文件,详情如下:
两个文件已经是排好序了的,因为 join命令只能对 已排序 的文件进行操作。
3.1、命令选项
join命令选项及其含义:
选项 |
含义 |
-a1 或 -a2 |
除了显示以共同域进行连接的结构外,-a1还显示第1个文件中没有共同域的记录,-a2表示显示第2个文件中没有共同域的记录。 |
-i |
比较域内容时,忽略大小写差异 |
-o |
设置结果显示的格式 |
-t |
改变域分隔符 |
-v1 或 -v2 |
与 -a 选项类似,不显示以共同与进行连接的结果 |
-1 和 -2 |
-1 用于设置文件1用于连接的域,-2用于设置文件2用于连接的域 |
join命令的基本语法为:
join [选项] 文件1 文件2
3.1.1、-a 和 -v 选项
当两个文件进行连接时,两个文件的记录可能找不到共同域,join命令的结果默认是不显示这些未进行连接的记录。
-a 和 -v 选项就是用于显示这个未进行连接的记录。-a1和-v1指显示文件1中未连接的记录,而 -a2 和 -v2 指显示文件2中未连接的记录。
-a 和 -v 选项的区别在于:-a 选项显示以共同域进行连接的结果,而 -v 选项则不显示这些记录。
-a 选项 除了显示连接成功连接的记录之外,还分别显示 TEACHER.txt、TEACHER_HOBBY.txt中未进行连接的记录。
-v 选项 只显示两个文件中未进行连接的记录。
3.1.2、-o 选项
join命令默认显示连接记录在两个文件中的所有域,而且是按顺序来显示的。-o 选项用于改变结果显示的格式。
"-o1.1 2.2 1.2",表示显示格式依次显示第1个文件中的第1个域,第2个文件的第2个域、第1个文件的第2个域。
3.1.3、-1 和 -2 选项
join命令默认比较文件1和文件2的第1域,如果需要通过其他域进行连接,需要使用 -1 和 -2 选项,-1 用于设置文件1用于连接的域,-2 用于设置文件2用于连接的域。
新建地区码文件 AREACODE.txt,存放城市及地区码 详情如下:
BEIJING:86010
HONGKONG:852
SHANGHAI:86021
TORONTO:001416
TEACHER.txt 的第三域是城市名,为了将 TEACHER.txt 的城市名与 AREACODE.txt 的城市名进行连接,首先要将 TEACHER.txt 按城市名排序,并将排序结果保存到 TEACHER1.txt文件。
join命令使用"-1 3 -2 1"选项指定用于连接的域,"-1 3"表示文件1的第3域,"-2 1"表示文件2的第1域。
由于AREACODE.txt的城市名是大写字母,因此,join带上 -i 选项表示在比较域时,忽略大小写,join的结果显示出城市名、姓名、学校、国家和地区码。
若不对 TEACHER.txt 进行排序,直接进行join操作,join命令会出错,提示文件1未排序。
出现 TEACHER.txt 未排序的报错。
4、cut命令
cut命令用于从标准输入或文本文件中按域或行提取文件,cut命令的基本格式为:
cut [选项] 文件
cut命令选项及其意义列表如下:
选项 |
含义 |
-c |
指定提取的字符数或字符返回 |
-f |
指定提取的域数或域范围 |
-d |
改变域分隔符 |
cut命令的选项有三个,-c 用于按字符提取文件,-f用于按域提取文件,-d类似于 sort 和 join 命令的 -t 选项,用于改变域分隔符。
-c 后跟数字表示字符数或字符范围,共有三种表示方法:1、-cn 表示第n个字符;2、-cn,m表示第n个字符和第m个字符;3、-cn-m 表示第 n 个字符到 第 m 个 字符。
由于 -c 选项是按字符提取文本的,因此无须使用 -d 改变域分隔符,但是,当使用 -f 域提取文本时,需要使用 -d 根据实际文本来设置域分隔符。
cut命令的 -f 选项按域提取TEACHER.txt文本,-f与-c选项一样,可使用三种方式指定域数或域范围,-f1-3 表示提取 TEACHER.txt的第 1 ~ 3 域。
5、paste 命令
paste命令用于将文本文件或标准输出中的内容粘贴到新的文件,可以将来自不同文件的数据粘贴到一起,形成新的文件。paste命令的基本格式是:
paste [选项] 文件1 文件2
paste命令有三个选项,详情如下:
选项 |
含义 |
-d |
默认域分隔符是空格或Tab键,设置新的域分隔符 |
-s |
将每个文件粘贴成一行 |
- |
从标准输入中读取数据 |
粘贴 file1 和 file2 详情如下:
-d 选项,指定分隔符,sort、join、cut命令改变域分隔符是为了按域读取文件内容,paste命令不同,改变域分隔符是用于设置输出文件的格式。
paste命令默认是将一个文件按列粘贴的,-s 选项可以实现将一个文件按行粘贴。
file1 和 file2 粘贴成新文件时,加上 -s 选项,FILE1内容被放到同一行,域之间以";"分隔,FILE2内容被粘贴到第2行同样以":"风格。
paste不加 -s 选项时,文件内容按列输出,加上 -s 选项后,文件内容按行输出。
paste命令的 "-" 选项较为特殊,当paste命令从标准输入中读取数据时,"-"选项才起作用。
paste命令通过读取ls命令的输出结果,再进行粘贴。paste命令后的 -d" " 将分隔符设置成空格符,在原本应出现 "文件1" 和 "文件2"的位置上加上"-" 选项,每行显示一个文件名,每个"-"选项表示读取1此标准输入数据,即读取到标准输入数据中的一个域。
6、split命令
split命令用于将大文件切割成小文件,split命令可以按照文件的行数、字节数切割文件,并能在输出的多个小文件中自动加上标号。
split命令的基本格式如下:
split [选项] 待切割的大文件 输出的小文件
split命令的选项用于指定切割的依据,将split命令的选项显示如下:
选项 |
含义 |
-或-1 |
指定切割成小文件的行数 |
-b |
指定切割成小文件的字节 |
-C |
切割时尽量维持每行的完整性 |
分隔大文件为小文件,详情如下:
split命令利用 -2 自定按2行对TEACHER.txt进行切割,即每2行记录切割成1个文件。small.txt为指定输出小文件名,split命令在small.txt后面自动加上编号以区分不同的小文件,编号aa~zz,即第1个小文件是 small.txtaa,第2个是small.txtab.
-b 和 -C 选项都是用于指定小文件的字节数,两个选项都是按照文件大小来切割文件,详情如下:
使用 ll 命令查看 TEACHER.txt 文件的大小,大小为180B,将 TEACHER.txt 按每100B切割成小文件,为指定小文件的名称,就以 x 加上 aa~zz的编号命令。
查看切割的小文件时,发现内容不完整,split命令-b选项在切割文件时仅考虑了文件大小,未考虑记录的完整性。
使用 -C 选项进行切割,详情如下:
利用 -C 选项按 90B 切割TEACHER.txt文件,得到三个小文件,但是 xaa 是 50B,xab 是 80B,xac是 47B,xaa、xab、xac者三个文件存放了完整的记录。
-C选项并不严格按照 90B 大小进行切割,而是在切割时尽量维持每行的完整性。
7、tr命令
tr命令实现字符转换功能,类似于sed命令,tr命令比sed命令简单,tr命令能实现的功能,sed命令都可以实现。
tr [选项] 字符串1 字符串2 <输入文件
tr命令有三个选项,tr命令可以跟两个字符串,大多数情况下,只能跟一个字符串。"<输入文件"表示将输入文件重定向到标准输入,tr命令与sort、uniq、join命令不同,只能从标准输入读取数据。
选项 |
含义 |
-c |
选定字符串1中字符集的补集,反选字符串1中的字符集 |
-d |
删除字符串1中出现的所有字符 |
-s |
删除所有重复出现的字符序列,只保留一个 |
tr命令的 -d 选项只需要跟一个字符串,表示删除字符串中出现的所有字符:
-s 选项用于删除所有重复出现的字符序列,只保留一个,即将重复出现的字符串压缩为一个字符。
AREACODE.txt文件包含若干空白行,空白行可看做改行只有一个换行符,无其他任何字符。只要将重复出现的换行符压缩成一个就可消除空白行。
tr命令加上字符串1和字符串2,将字符串1用字符串2来替换。如上将 大写字母换成小写字母。
8、tar命令
tar命令是Linux的归档命令,tar命令实现了Linux系统文件的压缩和解压缩。
tar命令的基本格式:
tar [选项] 文件名或目录名
tar的常用选项如下:
选项 |
含义 |
-c |
创建新的包 |
-r |
为包添加新的文件 |
-t |
列出包内容 |
-u |
更新包中的文件,若包中无此文件,则将该文件添加到包中 |
-x |
解压缩文件 |
-f |
使用压缩文件或设备,该选项通常是必选的 |
-v |
详细报告tar处理文件的信息 |
-z |
用gzip压缩和解压缩文件,若加上此选项创建压缩包,解压缩时也需要加上此选项 |
tar命令压缩文件和查看压缩包文件详情:
-r 选项,向压缩包添加文件:
tar命令中拥有解压缩功能,解压通用命令:
tar -xvf 压缩包名称
tar -zxvf 压缩包名称
加上 -z 选项可以解压用 gzip 压缩的文件,不加 -z 选项解压非 gzip 压缩的文件。-x 选项表示解压缩文件, -v 选项能生成解压缩过程的状态信息, -f 选项时必选选项。
利用tar命令解压file.all包,由于file.all非gzip格式,当加上-z选项时,解压出错,去掉 -z 选项解压成功,因-v 选项的存在,tar命令自动生成被解压出的文件信息。
tar -cf 命令创建的包,实际上是将多个文件放到一起,此时文件并没有被压缩,gzip命令是Linux系统中常用的压缩工具,可以对tar命令创建的包进行压缩。
gzip命令压缩file.all包,生成名为file.all.gz的文件,file.all.gz和file.all的内容是一样的,但file.all.gz文件经过了压缩,占用空间比较小。
由于file.all.gz是gzip格式的压缩文件,利用tar命令进行解压时,需添加 -z 选项。
gzip命令可将file.all.gz还原到file.all文件,只要在gzip命令后面加上-d选项即可。
9、总结
sort命令是一种文本排序工具
uniq命令可去除文本的重复记录,而且可以统计重=重复文本行的数量
join命令实现类似于关系数据库中的连接操作
cut命令用于从标准输入或文本文件中按域或行提取文本
paste命令用于将多个文本文件或标准输出中的内容粘贴而形成新的文件
split命令用于将大文件切割成小文件
tr命令实现字符转换功能,可以实现文本文件的过滤功能
tar命令是Linux的归档命令,tar命令和gzip命令用于实现Linux系统文件的压缩和解压缩。