Linux Shell 脚本编程(10)—文本过滤(合并与分割—sort、uniq、join、cut、paste、split)
文本过滤
- 正则表达式 —Linux Shell 脚本编程(5)—文本过滤(正则表达式)
- grep 命令 —Linux Shell 脚本编程(6)—文本过滤(grep命令)
- find命令 —Linux Shell 脚本编程(7)—文本过滤(find命令)
- awk命令 —Linux Shell 脚本编程(8)—文本过滤(awk命令)
- sed命令 —Linux Shell 脚本编程(9)—文本过滤(sed命令)
- 合并与分割(sort、uniq、join、cut、paste、split) —
sort命令
- 它将文件进行排序,并将排序结果标准输出。sort命令既可以从特定的文件,也可以从stdin中获取输入。
如果 File 参数指定多个文件,那么 sort 命令将这些文件连接起来,并当作一个文件进行排序。
格式 sort [选项] file(s)
1. 选项
option | 意义 |
---|---|
-b | 忽略每行前面开始出的空格字符 |
-c | 检查文件是否已经按照顺序排序; |
-g | general-numeric-sort —-按照常规数值排序 |
-i | 排序时,除了040至176之间的ASCII字符外,忽略其他的字符; |
-m | 将几个排序号的文件进行合并; |
-n | –numeric-sort 根据字符串数值比较 |
-M | 将前面3个字母依照月份的缩写进行排序; |
-n | 依照数值的大小排序; |
-o<输出文件> | 将排序后的结果存入制定的文件; |
-r | 以相反的顺序来排序; |
-u | 去重,就是 uniq ,相同的数据中,仅出现一行代表; |
-t<分隔字符> | 指定排序时所用的栏位分隔字符,默认是用 [tab] 键来分隔; |
-k <数字n> | 按照指定的区间 (field)[第n栏数据]来进行排序 |
+<起始栏位>-<结束栏位> | 以指定的栏位来排序,范围由起始栏位到结束栏位的前一栏位。 |
2. 实例
2.1 默认情况下是按ASCII值进行比较,升序排序输出(将文件/文本的每一行作为一个单位,相互比较,比较原则是从首字符向后进行)
#字符文本
jianliu@ubuntu:~/aa$ cat test0.txt
aaa:10:1.1
ccc:30:3.3
eee:50:5.5
ddd:40:4.4
bbb:20:2.2
eee:50:5.5
jianliu@ubuntu:~/aa$ sort test0.txt
aaa:10:1.1
bbb:20:2.2
ccc:30:3.3
ddd:40:4.4
eee:50:5.5
eee:50:5.5
#数字文本( 会出现2比10的情况,因为默认是比较ASCII码,按字符处理)
jianliu@ubuntu:~/aa$ cat test1.txt
23
10
2
345
4
10
23
55
jianliu@ubuntu:~/aa$ sort test1.txt
10
10
2
23
23
345
4
55
2.2 -u, 去重,忽略相同行(与uniq命令类似)
jianliu@ubuntu:~/aa$ sort -u test0.txt
aaa:10:1.1
bbb:20:2.2
ccc:30:3.3
ddd:40:4.4
eee:50:5.5
jianliu@ubuntu:~/aa$ cat test1.txt | sort -u
10
2
23
345
4
55
jianliu@ubuntu:~/aa$ sort -u < test1.txt
10
2
23
345
4
55
2.3 -n, 按常规数字大小进行排序
jianliu@ubuntu:~/aa$ sort -n test1.txt
2
4
10
10
23
23
55
345
jianliu@ubuntu:~/aa$ sort -nu test1.txt
2
4
10
23
55
345
jianliu@ubuntu:~/aa$ sort -n test0.txt
aaa:10:1.1
bbb:20:2.2
ccc:30:3.3
ddd:40:4.4
eee:50:5.5
eee:50:5.5
2.3 -r, 以相反的顺序进行排序(倒序)
jianliu@ubuntu:~/aa$ sort -nu -r test1.txt
345
55
23
10
4
2
jianliu@ubuntu:~/aa$ sort -u -r test0.txt
eee:50:5.5
ddd:40:4.4
ccc:30:3.3
bbb:20:2.2
aaa:10:1.1
2.4 -k 指定排序准则参照的域(对哪个域进行排序,结合-t选项一起使用)
- -k选项的语法:
# ----Start-------------,--------End--------
FStart.CStart Modifier, FEnd.CEnd Modifier
- 分为Start部分和End部分。 Modifier就是n,r,u等选项。
- Start部分:
FStart表示使用的起始域(排序的参考)
CStart 则表示在FStart域中从第几个字符开始算“排序首字符”,即从FStart域的第CStart位作为起点;可以省略,则表示从本域的开头部分开始 End部分
FEnd表示使用的结尾域(排序的参考)
CEnd则表示在FEnd域中从第几个字符开始算“排序尾字符”,即从FEnd域的第CEnd位作为域2尾;可以省略,则表示结尾到“域尾”,即本域的最后一个字符。 若将CEnd=0,表示结尾到“域尾”(1)对第2个域开始到最后一个域位置的内容进行排序
#该文本有三栏,每一栏数据被:分隔符分开。
jianliu@ubuntu:~/aa$ cat test0.txt
ABC:BB:CC
DFG:30:FF
afe:10:1.1
cfa:20:3.3
eea:40:4.5
dck:50:2.4
bdn:30:3.4
ecb:40:5.5
#按数值大小进行排序,没有去重
jianliu@ubuntu:~/aa$ sort -n -k 2 -t: test0.txt
ABC:BB:CC
afe:10:1.1
cfa:20:3.3
bdn:30:3.4
DFG:30:FF
ecb:40:5.5
eea:40:4.5
dck:50:2.4
#按数值大小进行排序,去重
jianliu@ubuntu:~/aa$ sort -un -k 2 -t: test0.txt
ABC:BB:CC
afe:10:1.1
cfa:20:3.3
DFG:30:FF
eea:40:4.5
dck:50:2.4
jianliu@ubuntu:~/aa$ sort -k 2n -t: test0.txt
ABC:BB:CC
afe:10:1.1
cfa:20:3.3
bdn:30:3.4
DFG:30:FF
ecb:40:5.5
eea:40:4.5
dck:50:2.4
jianliu@ubuntu:~/aa$ sort -u -k 2n -t: test0.txt
ABC:BB:CC
afe:10:1.1
cfa:20:3.3
DFG:30:FF
eea:40:4.5
dck:50:2.4
- (2)仅仅对第3个域的内容进行排序,按照数值大小升序。
jianliu@ubuntu:~/aa$ cat test0.txt
ABC:BB:CC
DFG:30:FF
afe:10:1.1
cfe:20:3.3
eea:40:4.5
dck:50:2.4
bdn:30:3.4
ecb:40:5.5
jianliu@ubuntu:~/aa$ cat test0.txt | sort -t ':' -n -k 3,3
ABC:BB:CC
DFG:30:FF
afe:10:1.1
dck:50:2.4
cfe:20:3.3
bdn:30:3.4
eea:40:4.5
ecb:40:5.5
- (3)对第1个域的第2个字符到第一栏的第3个字符进行排序,升序。
jianliu@ubuntu:~/aa$ cat test0.txt
ABC:BB:CC
DFG:30:FF
afe:10:1.1
cfe:20:3.3
eea:40:4.5
dck:50:2.4
bdn:30:3.4
ecb:40:5.5
jianliu@ubuntu:~/aa$ cat test0.txt | sort -t ':' -k 1.2,1.3
ABC:BB:CC
ecb:40:5.5
dck:50:2.4
bdn:30:3.4
eea:40:4.5
afe:10:1.1
cfe:20:3.3
DFG:30:FF
#再根据域2进行反序输出
jianliu@ubuntu:~/aa$ cat test0.txt | sort -t ':' -k 1.2,1.3 -k 2r
ABC:BB:CC
ecb:40:5.5
dck:50:2.4
bdn:30:3.4
eea:40:4.5
cfe:20:3.3
afe:10:1.1
DFG:30:FF
uniq命令
- uniq命令可以去除排序过后的文件中的重复行,因此经常和sort合用。
- 为使uniq起作用,所有的重复行必须是相邻的。
1. uniq 语法格式
- uniq [-icu] (参数)
- -i : 忽略大小写字符的不同;
- -c : 进行计数,在每列旁边显示该行重复出现的次数;
- -u : 只显示唯一的行(不重复的行),即重复的行数据,一个都不显示。
- -d : 仅显示重复出现的行列;
- -s<字符位置> : 忽略比较指定的字符
- -f<栏位> : 忽略比较指定的栏位
- -w<字符位置> : 指定要比较的字符。
- -i : 忽略大小写字符的不同;
2. 参数
- 输入文件:指定要去除的重复行文件。如果不指定此项,则从标准读取数据;
- 输出文件:指定要去除重复行后的内容要写入的输出文件。如果不指定此选项,则将内容显示到标准输出设备(显示终端)。
3. 测试实例
- 直接对文件进行uniq操作,只会对相邻的重复行进行去重,不处于相邻位置的重复数据行不会被删除!!
jianliu@ubuntu:~/aa$ cat test1.txt
kang dian feng
cao xiao qing
cao xiao qing
zhang yi shang
hello world
zhang jian
hello world
jianliu@ubuntu:~/aa$ uniq test1.txt
kang dian feng
cao xiao qing
zhang yi shang
hello world
zhang jian
hello world
- 对文件进行排序,再执行uniq
sort file | uniq 等价于 sort -u file
jianliu@ubuntu:~/aa$ cat test1.txt | sort -r | uniq
zhang yi shang
zhang jian
kang dian feng
hello world
cao xiao qing
jianliu@ubuntu:~/aa$ sort -ur test1.txt
zhang yi shang
zhang jian
kang dian feng
hello world
cao xiao qing
- 只显示唯一不重复行
jianliu@ubuntu:~/aa$ uniq -u test1.txt
kang dian feng
zhang yi shang
hello world
zhang jian
hello world
jianliu@ubuntu:~/aa$ sort test1.txt | uniq -u
kang dian feng
zhang jian
zhang yi shang
- 统计各行在文件中出现的次数,在行首显示重复的次数
jianliu@ubuntu:~/aa$ sort test1.txt | uniq -c
2 cao xiao qing
2 hello world
1 kang dian feng
1 zhang jian
1 zhang yi shang
- 在文件中找出重复的行
jianliu@ubuntu:~/aa$ sort test1.txt | uniq -d
cao xiao qing
hello world
cut 命令
1. cut命令说明
- cut命令用来显示行中的指定部分,删除文件中指定字段。
- cut命令对文本的列(字段)进行操作!!
cut经常用来显示文件的内容,类似于type命令。
该命令有两项功能,
- 用来显示文件的内容,它依次读取由参数file所指明的文件,将它们的内容输出到标准输出上;
- 其二是连接两个或多个文件,如cut fl f2 >f3将把文件fl和几的内容合并起来,然后通过输出重定向符“>”的作用,将它们放入文件f3中。
一般用more等命令分屏显示。为了控制滚屏,可以按Ctrl+S键,停止滚屏;
按Ctrl+Q键可以恢复滚屏。按Ctrl+C(中断)键可以终止该命令的执行,并且返回Shell提示符状态。语法格式
cut [选项] file
2. 选项
option | 意义 |
---|---|
-b | 仅显示行中指定直接范围的内容; |
-c | 仅显示行中指定范围的字符(字符区间); |
-d | 指定字段的分隔符,默认的字段分隔符为“TAB”; |
-f | 显示指定字段的内容;依据 -d 的分隔符将一行信息分割成为数段,用 -f n取出第n段数据 |
-n | 与“-b”选项连用,不分割多字节字符; |
–complement | 提取指定字节、字符或字段之外的列; |
–help | 显示指令的帮助信息; |
–version | 显示指令的版本信息。 |
3. 测试实例
3.1 -f,-d 提取指定栏字段内容
jianliu@ubuntu:~/aa$ cat test0.txt
ABC:BB:CC
DFG:30:FF
afe:10:1.1
cfe:20:3.3
eea:40:4.5
dck:50:2.4
bdn:30:3.4
ecb:40:5.5
#提取第二栏字段数据。分隔符为:
jianliu@ubuntu:~/aa$ cut -d ':' -f 2 test0.txt
BB
30
10
20
40
50
30
40
#提取第2,3栏字段数据
jianliu@ubuntu:~/aa$ cut -d ':' -f 2,3 test0.txtBB:CC
30:FF
10:1.1
20:3.3
40:4.5
50:2.4
30:3.4
40:5.5
3.2 –complement, 提取指定字段之外的列
#提取第二栏列数据-----
jianliu@ubuntu:~/aa$ cut -d ':' -f2 --complement test0.txt
ABC:CC
DFG:FF
afe:1.1
cfe:3.3
eea:4.5
dck:2.4
bdn:3.4
ecb:5.5
3.3 -c -b 提取指定字段的字符或者字节区间。
- cut -d 分隔符 -c 字符区间 file ==>用于排列整齐的信息
字符区间写法
- (1) N- : 从第N个字节、字符、字段到结尾
- (2) N-M : 从第N个字节/字符/字段到第M个(包括M在内)字节/字符/字段;
- (3) -M : 从第1个字节/字符/字段到第M个(包括M在内)字节/字符/字段
- 范围的类型
- -b : 字节
- -c : 字符
- -f : 定义字段
打印第1——第3个字符
jianliu@ubuntu:~/aa$ cut -c1-3 test0.txt
ABC
DFG
afe
cfe
eea
dck
bdn
ecb
#打印前4个字符
jianliu@ubuntu:~/aa$ cut -c-4 test0.txt
ABC:
DFG:
afe:
cfe:
eea:
dck:
bdn:
ecb:
#打印从第5个字符开始到结尾
jianliu@ubuntu:~/aa$ cut -c5- test0.txt
BB:CC
30:FF
10:1.1
20:3.3
40:4.5
50:2.4
30:3.4
40:5.5
join 命令
- join命令两个文件中,制定栏位内容相同的行连接起来。找出两个文件中,指定栏位内容相同的行,并加以合并,再输出到标准输出设备
语法格式
join 选项 (file1 file2)注:这两个文件必须在已经在此列上是依照同样的规则进行了排序。因此
在使用join前,应先sort排序
1. 选项
-a<1或2>:除了显示原来的输出内容之外,还显示指令文件中没有相同栏位的行;
-e<字符串>:若[文件1]与[文件2]中找不到指定的栏位,则在输出中填入选项中的字符串;
-i或--ignore-case:比较栏位内容时,忽略大小写的差异;
-j FIELD :等同于 -1 FIELD -2 FIELD,-j指定一个域作为匹配字段
-o<格式>:按照指定的格式来显示结果;
-t<字符>:使用栏位的分割字符;
-v<1或2>:更-a相同,但是只显示文件中没有相同栏位的行;
-1<栏位FIELD>:连接[文件1]指定的栏位;
-2<栏位FIELD>:连接[文件2]指定的栏位。
2. 实例操作
- 两个文本文件如下;
jianliu@ubuntu:~/aa$ cat test0.txt
aaa:1:2
bbb:2:3
ccc:3:6
ddd:4:3
eee:5:5
jianliu@ubuntu:~/aa$ cat test1.txt
aaa:2:1
bbb:6:2
ccc:2:3
fff:4:4
ddd:5:4
- 默认以第一列作为匹配字段,默认以空格(不限格式)作为分隔符。 -t设置分隔符
jianliu@ubuntu:~/aa$ join -t ':' test0.txt test1.txt
aaa:1:2:2:1
bbb:2:3:6:2
ccc:3:6:2:3
join: test1.txt:5: is not sorted: ddd:5:4
- -j 数字N 指定以两个文件每一行中第N列作为匹配字段
jianliu@ubuntu:~/aa$ join -t ':' -j 1 test0.txt test1.txt
aaa:1:2:2:1
bbb:2:3:6:2
ccc:3:6:2:3
join: test1.txt:5: is not sorted: ddd:5:4
jianliu@ubuntu:~/aa$ join -t ':' -j 2 test0.txt test1.txt
2:bbb:3:aaa:1
join: test1.txt:3: is not sorted: ccc:2:3
- -1 数字M -2 数字N file1 file2 以file1的第M列和file2的第N列作匹配字段。
jianliu@ubuntu:~/aa$ join -t ':' -1 2 -2 3 test0.txt test1.txt
1:aaa:2:aaa:2
2:bbb:3:bbb:6
3:ccc:6:ccc:2
4:ddd:3:fff:4
4:ddd:3:ddd:5
#最后两行的行首均为4,是因为test0.txt中第4行和test1.txt中的第4、5行均匹配。
- -o 控制输出格式
jianliu@ubuntu:~/aa$ join -t ':' -o 1.1 -o 1.2 -o 1.3 -o 2.1 -o 2.2 -o 2.3 -e 'empty_' -a 1 test0.txt test1.txt
aaa:1:2:aaa:2:1
bbb:2:3:bbb:6:2
ccc:3:6:ccc:2:3
ddd:4:3:empty_:empty_:empty_
eee:5:5:empty_:empty_:empty_
join: test1.txt:5: is not sorted: ddd:5:4
#-o 指定 将file1的1,2,3列,file2的1,2,3 列都输出。
#-a指定将file1中不匹配的行也输出-e选项指示未匹配的部分使用empty补齐。
- -v 输出不匹配的行
# -v 1 表示显示file1中的不匹配数据
jianliu@ubuntu:~/aa$ join -t ':' -j 1 -v 1 test0.txt test1.txt
ddd:4:3
eee:5:5
join: test1.txt:5: is not sorted: ddd:5:4
jianliu@ubuntu:~/aa$ join -t ':' -j 1 -v 2 test0.txt test1.txt
fff:4:4
join: test1.txt:5: is not sorted: ddd:5:4
ddd:5:4
- 利用管道和字符‘-’将多个文件join到一起
#将多个格式同样的文件join到一起,而join接受的是两个文件的指令,此时我们能够使用管道和字符“-"来实现
join file1 file2 | join - file3 | join - file4
paste 命令
- paste命令用于将多个文件按照列(栏)进行合并成一个多列文件,列数为多个文件的列数之和。并按照源多个文件的列顺序进行列栏数据的排列(从左到右排起来)。
- 参考资料:http://www.cnblogs.com/cyf333333/p/5528689.html
1. 格式及选项
- paste 选项 file1 file2
选项
-d<分隔符>或--delimiters=<分隔符>: 用指定的分隔符分割拼接的列,列间分割标志;默认是空格。 -s或——serial 串列进行而非平行处理。
2. 实例说明
- 实例文本
jianliu@ubuntu:~/aa$ cat test0.txt
aaa
bbb
ccc
ddd
eee
fff
jianliu@ubuntu:~/aa$ cat test1.txt
111
222
333
444
555
666
- 直接进行拼接
jianliu@ubuntu:~/aa$ paste test0.txt test1.txt
aaa 111
bbb 222
ccc 333
ddd 444
eee 555
fff 666
- -d, 使用指定的分隔符隔开各个文件的列
jianliu@ubuntu:~/aa$ paste -d ':' test0.txt test1.txt
aaa:111
bbb:222
ccc:333
ddd:444
eee:555
fff:666
#-d之后使用双引号和单引号甚至不用引号的结果一样,而且只能指定一个字符,对于-d"::::----"仍然只有第一个字符会被取为分隔符.
- -s, 删除所有换行,即将所有行合并成一整行。可以用-d指定相邻行数据合并后的分隔符,默认是空格。
(1) paste file -s
jianliu@ubuntu:~/aa$ paste test0.txt -s
aaa bbb ccc ddd eee fff
jianliu@ubuntu:~/aa$ paste test0.txt -s -d:
aaa:bbb:ccc:ddd:eee:fff
(2)paste file1 file2 -s
每个文件内容变成一行,最终结果为二行,按照文件顺序输出。
jianliu@ubuntu:~/aa$ paste test0.txt test1.txt -s
aaa bbb ccc ddd eee fff
111 222 333 444 555 666
jianliu@ubuntu:~/aa$ paste test0.txt test1.txt -s -d:
aaa:bbb:ccc:ddd:eee:fff
111:222:333:444:555:666
split 命令
- split命令可以将一个大文件分割成很多个小文件,有时需要将文件分割成更小的片段,比如为提高可读性,生成日志等
- 参考文献:http://man.linuxde.net/split、
1. split命令格式及选项
- 格式: split 选项 file
- 选项
-b: 值为每一输出档案的大小,单位为 byte。
-C: 每一输出档中,单行的最大 byte 数。
-d: 使用数字作为后缀。
-l: 值为每一输出档的列数大小。
2. 实例测试
- 测试文件(大小200KB)
jianliu@ubuntu:~/ccc$ dd if=/dev/zero bs=200K count=1 of=date.file
1+0 records in
1+0 records out
204800 bytes (205 kB) copied, 0.000256486 s, 798 MB/s
jianliu@ubuntu:~/ccc$ ls -l
total 200
-rw-rw-r-- 1 jianliu jianliu 204800 Oct 19 07:55 date.file
jianliu@ubuntu:~/ccc$ chmod a+x date.file
jianliu@ubuntu:~/ccc$ ls -l
total 200
-rwxrwxr-x 1 jianliu jianliu 204800 Oct 19 07:55 date.file
- 将date.file分割成大小为20KB的多个小文件
jianliu@ubuntu:~/ccc$ split -b 20k date.file
jianliu@ubuntu:~/ccc$ ls -l
total 400
-rwxrwxr-x 1 jianliu jianliu 204800 Oct 19 07:55 date.file
-rw-rw-r-- 1 jianliu jianliu 20480 Oct 19 07:59 xaa
-rw-rw-r-- 1 jianliu jianliu 20480 Oct 19 07:59 xab
-rw-rw-r-- 1 jianliu jianliu 20480 Oct 19 07:59 xac
-rw-rw-r-- 1 jianliu jianliu 20480 Oct 19 07:59 xad
-rw-rw-r-- 1 jianliu jianliu 20480 Oct 19 07:59 xae
-rw-rw-r-- 1 jianliu jianliu 20480 Oct 19 07:59 xaf
-rw-rw-r-- 1 jianliu jianliu 20480 Oct 19 07:59 xag
-rw-rw-r-- 1 jianliu jianliu 20480 Oct 19 07:59 xah
-rw-rw-r-- 1 jianliu jianliu 20480 Oct 19 07:59 xai
-rw-rw-r-- 1 jianliu jianliu 20480 Oct 19 07:59 xaj
- -d, 指定分割的小文件的后缀名称为数字后缀; -a,指定后缀的长度
jianliu@ubuntu:~/ccc$ split -b 20K date.file -d -a 4
jianliu@ubuntu:~/ccc$ ls
date.file x0000 x0001 x0002 x0003 x0004 x0005 x0006 x0007 x0008 x0009
- 指定分割后文件的文件名前缀
date.file split_0001 split_0003 split_0005 split_0007 split_0009
split_0000 split_0002 split_0004 split_0006 split_0008
- -l,根据文件的行数来分割文件
#,文件分割成每个包含10行的小文件:
jianliu@ubuntu:~/ccc$ split -l 10 date.file -d -a 4 split_
jianliu@ubuntu:~/ccc$ ls
date.file split_0000