shell基础11:文件分类、合并和分割(sort,uniq,join,cut,paste,split)

用uniq命令可以删除相邻的重复行:

  uniq [file]

  但如果一文本中有重复却不相邻的行则无法删除,需要结合sort命令:

  sort [file]|uniq

  等效的sort命令是:

  sort -u [file]

  另外uniq命令有4个有用的选项:

  $uniq -d file 只输出file中的重复行,且只输出一次,但不输出唯一的行

  $uniq -u file 只输出file中的唯一行(当然是一次啦)

  $uniq -c file 在每行前显示重复次数,可与其他选项结合,例如-cu或-cd或-c

  $uniq -i file 比较时忽略大小写

  -d的结果和-u的结果合并起来就是uniq的结果了。

sort用法
s o r t命令选项很长,下面仅介绍各种选项。
选项
s o r t命令的一般格式为:

  1. sort -cmu -o output_file [other options] +pos1 +pos2 input_files
复制代码

下面简要介绍一下s o r t的参数:

-c 测试文件是否已经分类。
-m 合并两个分类文件。
-u 删除所有复制行。
-o 存储s o r t结果的输出文件名。

其他选项有:
-b 使用域进行分类时,忽略第一个空格。
-n 指定分类是域上的数字分类。
-t 域分隔符;用非空格或t a b键分隔域。
-r 对分类次序或比较求逆。
+n n为域号。使用此域号开始分类。
n n为域号。在分类比较时忽略此域,一般与+ n一起使用。
post1 传递到m,n。m为域号,n为开始分类字符数;例如4,6意即以第5域分类,从第7个字符开始。
基本sort
最基本的s o r t方式为sort filename,按第一域进行分类(分类键0)。实际上读文件时s o r t操作将行中各域进行比较,这里返回基于第一域s o r t的结果
  1. [sam@Linux_chenwy sam]$ sort -t: video.txt
  2. A Few Good Men:KL:445:5851
  3. Alien:HK:119:1982
  4. Aliens:HK:532:4892
  5. Boys in Company C:HK:192:2192
  6. Star Wars:HK:301:4102
  7. The Hill:KL:63:2972
  8. Toy Story:HK:239:3972
复制代码

要只使用供应区代码后缀部分将文件分类,其命令为+ 1 . 2,意即以第1域最左边第3个字符开始分类

sort -t: +1.2 video.txt

、为了更好地进行控制,您可以使用键和偏移量。偏移量是用点与键相分隔的,比如在 -k 1.3,5.7 中,表示排序键应当从第 1 个字段的第 3 个字符开始,到第 5 个字段的第 7 个字符结束(偏移量也是从 1 开始编号的)。何时会用得着偏移量呢?嗯,我时常用它来对 Apache 日志进行排序;键和偏移量表示法让我跳过了日期字段。

可以用下面这些选项来进一步修改排序算法:
-d(只将字母、数字和空白用作排序键)、
-f(关闭大小写区分,认为小写和大写字符是一样的)、
-i(忽略非打印的 ASCII 字符)、
-M(使用三个字母的月份名称缩写:JAN、FEB、MAR … 来对行进行排序)和 
-n(只用数字、- 和逗号或另外一个千位分隔符对行进行排序)。
这些选项以及 -b 和 -r 选项可以用作键编号的一部分,
在这种情况下,它们只适用于该键而非全局,其作用就跟在键定义外使用它时一样。

将两个分类文件合并
将文件合并前,它们必须已被分类。合并文件可用于事务处理和任何种类的修改操作。
下面这个例子,因为忘了把两个家电名称加入文件,它们被放在一个单独的文件里,现在将之并入一个文件。分类的合并格式为‘ sort -m sorted_file1 sorted_file2,下面是包含两个新家电名称的文件列表,它已经分类完毕:

  1. [sam@chenwy sam]$ cat video2.txt
  2. Crimson Tide:134:2031
  3. Die Hard:152:2981
复制代码

使用-m +o。将这个文件并入已存在的分类文件v i d e o . s o r t(Deven:与重定向合并还是不一样的),要以名称域进行分类,实际上没有必要加入+ o,但为了保险起见,还是加上的好。
  1. [sam@chenwy sam]$ sort -t: -m +0 video2.txt video.txt
  2. Boys in Company C:HK48:192:2192
  3. Alien:HK57:119:1982
  4. Crimson Tide:134:2031
  5. Die Hard:152:2981
  6. The Hill:KL223:63:2972
  7. Aliens:HK11:532:4892
  8. Star Wars:HK38:301:4102
  9. A Few Good Men:KL87:445:5851
  10. Toy Story:HK65:239:3972

 

uniq用法
u n i q用来从一个文本文件中去除或禁止重复行。一般u n i q假定文件已分类,并且结果正确。
我们并不强制要求这样做,如果愿意,可以使用任何非排序文本,甚至是无规律行。

可以认为u n i q有点像s o r t命令中唯一性选项。对,在某种程度上讲正是如此,但两者有一个重要区别。s o r t的唯一性选项去除所有重复行,而u n i q命令并不这样做。重复行是什么?在u n i q里意即持续不断重复出现的行,中间不夹杂任何其他文本,现举例如下: 

  1. cat test.txt
  2. May Day
  3. May Day
  4. May Day
  5. Going DOwn
  6. May Day
  7. May Day.
  8. May Day

sort -u test.txt 

Going DOwn

May Day

May Day.

[root@centos-5 ~]# uniq test.txt

May Day

Going DOwn

May Day

May Day.

May Day

[root@centos-5 ~]# uniq -u test.txt

Going DOwn

May Day

May Day.

May Day

u n i q将前三个May Day看作重复副本,但是因为第4行有不同的文本,故并不认为第五行持续的May Day为其副本。u n i q将保留这一行。

这就是为什么统计ip访问次数的时候要先sort再uniq -c的原因。 cat access_20110505.log |grep '2011:00:00'|awk '{print $1}'|sort|uniq -c|sort -n -r|head -n 50

命令一般格式:

其选项含义:
-u 只显示不重复行。
-d 只显示有重复数据行,每种重复行只显示其中一行
-c 打印每一重复行出现次数。
-f n为数字,前n个域被忽略。
一些系统不识别- f选项,这时替代使用- n
  1. uniq -c test.txt
  2.       3 May Day
  3.       1 Going DOwn
  4.       1 May Day
  5.       1 May Day.
  6.       1 May Day
 
2. 对特定域进行测试
使用- n只测试一行一部分的唯一性。例如- 5意即测试第5域后各域唯一性。域从1开始记数。

如果忽略第1域,只测试第2域唯一性,使用- n2,下述文件包含一组数据,其中第2域代表组代码。

 join用法

j o i n用来将来自两个分类文本文件的行连在一起。
下面讲述j o i n工作方式。这里有两个文件f i l e 1和f i l e 2,当然已经分类。每个文件里都有一些元素与另一个文件相关。由于这种关系, j o i n将两个文件连在一起,这有点像修改一个主文件,使之包含两个文件里的共同元素。
文本文件中的域通常由空格或t a b键分隔,但如果愿意,可以指定其他的域分隔符。一些系统要求使用j o i n时文件域要少于2 0,为公平起见,如果域大于2 0,应使用D B M S系统。
为有效使用j o i n,需分别将输入文件分类。
其一般格式为:
  1. join [options] input-file1 input-file2
复制代码

选项:
an n 为一数字,用于连接时从文件n中显示不匹配行。例如, - a 1显示第一个文件的不匹配行,- a 2为从第二个文件中显示不匹配行。
o n.m n为文件号,m为域号。1 . 3表示只显示文件1第三域,每个n,m必须用逗号分隔,如1 . 3,2 . 1。
j n m n为文件号,m为域号。使用其他域做连接域。
t 域分隔符。用来设置非空格或t a b键的域分隔符。例如,指定冒号做域分隔符- t:。


现有两个文本文件,其中一个包含名字和街道地址,称为n a m e . t x t,另一个是名字和城镇,
为t o w n . t x t。
  1. [sam@chenwy sam]$ cat names.txt
  2. M.Golls 12 Hidd Rd
  3. P.Heller The Acre
  4. P.Willey 132 The Grove
  5. T.Norms 84 Connaught Rd
  6. K.Fletch 12 Woodlea
复制代码

  1. [sam@chenwy sam]$ cat town.txt
  2. M.Golls Norwich NRD
  3. P.Willey Galashiels GDD
  4. T.Norms Brandon BSL
  5. K.Fletch Mildenhall MAF
  6. K.Firt Mitryl Mdt
复制代码
连接两个文件
连接两个文件,使得名字支持详细地址。例如M . G o l l s记录指出地址为12 Hidd Rd。连接域为域0—名字域。因为两个文件此域相同, j o i n将假定这是连接域:
  1. [sam@chenwy sam]$ join names.txt town.txt
  2. M.Golls 12 Hidd Rd Norwich NRD
  3. P.Willey 132 The Grove Galashiels GDD
  4. T.Norms 84 Connaught Rd Brandon BSL
  5. K.Fletch 12 Woodlea Mildenhall MAF
缺省j o i n删除或去除连接键的第二次重复出现,这里即为名字域。
1. 不匹配连接
如果一个文件与另一个文件没有匹配域时怎么办?这时j o i n不可以没有参数选项,经常指定两个文件的- a选项。下面的例子显示匹配及不匹配域。
  1. [sam@chenwy sam]$ join -a1 -a2 names.txt town.txt
  2. M.Golls 12 Hidd Rd Norwich NRD
  3. P.Heller The Acre
  4. P.Willey 132 The Grove Galashiels GDD
  5. T.Norms 84 Connaught Rd Brandon BSL
  6. K.Fletch 12 Woodlea Mildenhall MAF
  7. K.Firt Mitryl Mdt
  1. [sam@chenwy sam]$ join -a1  names.txt town.txt
  2. M.Golls 12 Hidd Rd Norwich NRD
  3. P.Heller The Acre
  4. P.Willey 132 The Grove Galashiels GDD
  5. T.Norms 84 Connaught Rd Brandon BSL
  6. K.Fletch 12 Woodlea Mildenhall MAF
2. 选择性连接
使用- o选项选择连接域。例如要创建一个文件仅包含人名及城镇, j o i n执行时需要指定显示域。方式如下:
使用1 . 1显示第一个文件第一个域,2 . 2显示第二个文件第二个域,其间用逗号分隔。命令为:
  1. [sam@chenwy sam]$ join -o 1.1,2.2 names.txt town.txt
  2. M.Golls Norwich
  3. P.Willey Galashiels
  4. T.Norms Brandon
  5. K.Fletch Mildenhall
使用-jn m进行其他域连接,例如用文件1域3和文件域2做连接键,命令为:
  1. [sam@chenwy sam]$ cat pers
  2. P.Jones Office Runner ID897
  3. S.Round UNIX admin ID666
  4. L.Clip Personl Chief ID982
  1. [sam@chenwy sam]$ cat pers2
  2. Dept2C ID897 6 years
  3. Dept3S ID666 2 years
  4. Dept5Z ID982 1 year
文件p e r s包括名字、工作性质和个人I D号。文件p e r s 2包括部门、个人I D号及工龄。连接应使用文件p e r s中域4,匹配文件p e r s 2中域2,命令及结果如下:
  1. [sam@chenwy sam]$ join -j1 4 -j2 2 pers pers2
  2. ID897 P.Jones Office Runner Dept2C 6 years
  3. ID666 S.Round UNIX admin Dept3S 2 years
  4. ID982 L.Clip Personl Chief Dept5Z 1 year
使用j o i n应注意连接域到底是哪一个,比如说你认为正在访问域4,但实际上j o i n应该访问域5,这样将不返回任何结果。如果是这样,用a w k检查域号。例如,键入$ awk '{print $4}'文件名,观察其是否匹配假想域。
cut用法
c u t用来从标准输入或文本文件中剪切列或域。剪切文本可以将之粘贴到一个文本文件。
c u t一般格式为:
  1. cut [options] file1 file2
下面介绍其可用选项:
-c list 指定剪切字符数。
-f field 指定剪切域数。
-d 指定与空格和t a b键不同的域分隔符。
- c用来指定剪切范围,如下所示:
- c 1,5-7 剪切第1个字符,然后是第5到第7个字符。
-c1-50 剪切前5 0个字符。
-f 格式与- c相同。
-f 1,5 剪切第1域,第5域。
- f 1,10-12 剪切第1域,第1 0域到第1 2域。
现在从' p e r s '文件中剪切文本。
  1. [sam@chenwy sam]$ cat pers
  2. P.Jones Office Runner ID897
  3. S.Round UNIX admin ID666
  4. L.Clip Personl Chief ID982
使用域分隔符
文件中使用空格“ ”为域分隔符,故可用- d选项指定冒号,如- d " "。如果有意观察第3域,可以使用- f 3。要抽取I D域。可使用命令如下:
  1. [sam@chenwy sam]$ cut -d" " -f3 pers
  2. Runner
  3. admin
  4. Chief
剪切指定域
c u t命令中剪切各域需用逗号分隔,如剪切域1和3,即名字和I D号,可以使用:
  1. [sam@chenwy sam]$ cut -d" " -f1,3 pers
  2. P.Jones Runner
  3. S.Round admin
  4. L.Clip Chief
使用- c选项指定精确剪切数目
这种方法需确切知道开始及结束字符。通常我不用这种方法,除非在固定长度的域或文件名上。
当信息文件传送到本机时,查看部分文件名就可以识别文件来源。要得到这条信息需抽取文件名后三个字符。然后才决定将之存在哪个目录下。下面的例子显示文件名列表及相应c u t命令:
  1. [sam@chenwy sam]$ cat pers2
  2. Dept2C ID897 6 years
  3. Dept3S ID666 2 years
  4. Dept5Z ID982 1 year
  1. [sam@chenwy sam]$ cut -c4-8,11-12 pers2
  2. t2C I97
  3. t3S I66
  4. t5Z I82
要剪切谁正在使用系统的用户信息,方法如下:
  1. [sam@chenwy sam]$ who -u|cut -c1-8
  2. root
  3. root

 paste用法

c u t用来从文本文件或标准输出中抽取数据列或者域,然后再用p a s t e可以将这些数据粘贴起来形成相关文件。粘贴两个不同来源的数据时,首先需将其分类,并确保两个文件行数相同。
p a s t e将按行将不同文件行信息放在一行。缺省情况下, p a s t e连接时,用空格或t a b键分隔新行中不同文本,除非指定- d选项,它将成为域分隔符。
p a s t e格式为;

  1. paste -d -s -file1 file2
选项含义如下:
-d 指定不同于空格或t a b键的域分隔符。例如用@分隔域,使用- d @。
-s 将每个文件合并成行而不是按行粘贴。
- 使用标准输入。例如ls -l |paste ,意即只在一列上显示输出。

从前面的剪切中取得下述两个文件:

  1. [sam@chenwy sam]$ cut -d" " -f 2 pers2 >pas1
  2. [sam@chenwy sam]$ cat pas1
  3. ID897
  4. ID666
  5. ID982
复制代码
  1. [sam@chenwy sam]$ cut -d" " -f1 pers >pas2
  2. [sam@chenwy sam]$ cat pas2
  3. P.Jones
  4. S.Round
  5. L.Clip

基本p a s t e命令将之粘贴成两列:

  1. [sam@chenwy sam]$ paste pas1 pas2
  2. ID897   P.Jones
  3. ID666   S.Round
  4. ID982   L.Clip

指定列
通过交换文件名即可指定哪一列先粘:

  1. [sam@chenwy sam]$ paste pas2 pas1
  2. P.Jones ID897
  3. S.Round ID666
  4. L.Clip  ID982

使用不同的域分隔符
要创建不同于空格或t a b键的域分隔符,使用- d选项。下面的例子用冒号做域分隔符。

  1. [sam@chenwy sam]$ paste -d: pas2 pas1
  2. P.Jones:ID897
  3. S.Round:ID666
  4. L.Clip:ID982

要合并两行,而不是按行粘贴,可以使用- s选项。下面的例子中,第一行粘贴为名字,第二行是I D号。

  1. [sam@chenwy sam]$ paste -s pas2 pas1
  2. P.Jones S.Round L.Clip
  3. ID897   ID666   ID982

paste命令管道输入
p a s t e命令还有一个很有用的选项( -)。意即对每一个( -),从标准输入中读一次数据。
使用空格作域分隔符,以一个4列格式显示目录列表。方法如下:

  1. [sam@chenwy sam]$ ls | paste -d" " - - - - -
  2. 1.bak 1.txt append.sed backll.ee change.sed
  3. data.f data.txt delete_me_and_die dht dir1
  4. ......................

一行显示四个文件,以空格分开

  1. [sam@chenwy sam]$ ls | paste -d: - - - - -
  2. 1.bak:1.txt:append.sed:backll.ee:change.sed
  3. data.f:data.txt:delete_me_and_die:dht:dir1
  4. .....................

一行显示四个文件,以冒号:分开
也可以以一列格式显示输出:

  1. [sam@chenwy sam]$ ls | paste -d" " -
  2. 1.bak
  3. 1.txt
  4. append.sed
  5. backll.ee
  6. ..................
  7. 一行显示一个文件

split用法
s p l i t用来将大文件分割成小文件。有时文件越来越大,传送这些文件时,首先将其分割可能更容易。使用v i或其他工具诸如s o r t时,如果文件对于工作缓冲区太大,也会存在一些问题。
因此有时没有选择余地,必须将文件分割成小的碎片。
s p l i t命令一般格式:

  1. split -output_file-size input-filename output-filename
这里o u t p u t - f i l e - s i z e指的是文本文件被分割的行数。
s p l i t查看文件时,o u t p u t - f i l e - s i z e选项指定将文件按每个最多1 0 0 0行分割。如果有个文件有38行,那么将分割成3个文件,分别有
10、10、10、8行。每个文件格式为x [ a a ]到x [ z z ],x为文件名首字母, [ a a ]、[ z z ]为文件名剩余部分顺序字符组合,下面的例子解释这一点。
如passwd有38行:
  1. [sam@chenwy split]$ ls -l
  2. 总用量 8
  3. -rw-r--r--    1 sam      sam          1649 12月  4 11:13 passwd
  4. -rw-rw-r--    1 sam      sam            84 12月  4 11:19 split1
复制代码
  1. [sam@chenwy split]$ split -10 passwd
  2. [sam@chenwy split]$ ls -l
  3. 总用量 24
  4. -rw-r--r--    1 sam      sam          1649 12月  4 11:13 passwd
  5. -rw-rw-r--    1 sam      sam            84 12月  4 11:19 split1
  6. -rw-rw-r--    1 sam      sam           368 12月  4 11:24 xaa
  7. -rw-rw-r--    1 sam      sam           474 12月  4 11:24 xab
  8. -rw-rw-r--    1 sam      sam           495 12月  4 11:24 xac
  9. -rw-rw-r--    1 sam      sam           312 12月  4 11:24 xad
复制代码
生成了四个文件,前三个文件每个文件10行,最后一个8行,分割分的文件名自动产生,格式为x[a-a][z-z]

 

你可能感兴趣的:(shell,sort)