【shell基础】01、常用的字符处理命令
目录wc,cut,sort,uniq,tr,paste,split
1、文本统计:wc
wc... ...
不指定选项默认:输出每个指定文件的行数、单词数和字节数,如果指定了多于一个文件,继续给出所有相关数据的总计。如果没有指定文件,或者文件为"-",则从标准输入读取数据。
-l, --lines 输出行数统计
-w, --words 统计单词数
-c, --bytes输出字节数统计
-m, --chars输出字符数统计
# cat test1
aaabbbccc #空格和换行符也都算1个字符
hello world
你好,世界 #中文1个算多个字符,没有中文时,字符数等于字节数
# wc test1
46 43 test1
# wc -l test1
4 test1
# wc -m test1
33 test1
# wc -c test1
43 test1
# wc test1
34 25 test1
# wc -l test1
3 test1
# wc -w test1
4 test1
# wc -c test1
25 test1
# wc -m test1
25 test1
2、字符截取:cut
从每个文件中输出指定部分到标准输出,它每次处理的对象是“一行”文本,从中选取出用户所需要的部分,返回的是列。默认以空格为分隔符,也可以指定特定的分隔符,然后打印出以分隔符隔开的集体某一列或某几列。
cut ... ..
-d:--delimiter=分界符 使用指定分界符代替制表符作为区域分界
-d ' ' :表示以空格为分隔符 #默认以制表符为分割符
-f #:指明要保留的字段(列)
单个: #
离散的多个:#,#,#
连续的多个:#-#
-s, --only-delimited 不打印没有包含分界符的行
# cut -f 1 test1
aaa bbb ccc
hello,world
# cut -d '' -f 1 test1
aaa bbb ccc
hello,world
# cut -d ' ' -f 1 test1
aaa
hello,world
# cut -s -d ' ' -f 1 test1
aaa
# cut -d ' ' -f 2 test1
bbb
hello,world
# cut -d ' ' -f 3 test1
ccc
hello,world
# cut -d ' ' -f 4 test1
hello,world
# cut -d ' ' -f 1,3 test1 #保留第一和第三列
aaa ccc
hello,world
# cut -d ' ' -f 1-3 test1 #保留第一到第三列
aaa bbb ccc
hello,world
# cat test2
abc de #一个tab键是制表符,c和d之间是1个空格,d和e之间2个空格
123 45
# cut -f 1 test2 #默认以制表符为分隔符
a
1
# cut -f 3 test2 #制表符和空格有区别
c de
3 45
# cut -d '' -f 3 test2 #引号之间不能没有空格
abc de
123 45
# cut -d ' ' -f 1 test2#再次说明制表符不等于4个空格
abc
123
# cut -d '' -f 1 test2 #不能以2个空格作为分隔符,必须是单个字符
cut: 分界符必须是单个字符
请尝试执行"cut --help"来获取更多信息。
# cut -d ' ' -f 2 test2
d
4
# cut -d ' ' -f 3 test2 #有多个空格时,以1个空格为分隔符后的列还是1个空格,所有分隔符是多个空格时,使用cut可能会有问题
# cut -d ":" -f 1,6-7 /etc/passwd#以“:”为分隔符
root:/root:/bin/bash
bin:/bin:/sbin/nologin
daemon:/sbin:/sbin/nologin
# cut -d ' ' -f 4 test2 #下一列
e
5
# echo "1aa2aa3"|cut -d 'a' -f 1
1
# echo "1aa2aa3"|cut -d 'a' -f 2
# echo "1aa2aa3"|cut -d 'a' -f 3
2
以上cut使用场景是在处理的行中有特定的分隔符的时候,但是如果要处理的行是没有分隔符的,那cut就没有用了吗?
cut还可以打印指定个数的字符或字节,这个时候cut的用法如下:
# cut -b 5 test1
b
o
# cut -b 5 test1 test2
b
o
c
3
# cut -b 5-10 test1 test2
bbb cc
o,worl
c de
3 45
# cut -c 5-10 test1 test2
bbb cc
o,worl
c de
3 45
# cut -c 5-100 test1 test2
bbb ccc
o,world
c de
3 45
3、文本排序:sort
串联排序所有指定文件并将结果写到标准输出
注意:这里说的排序是行的上,下排序;针对的行不是列
sort ... ...
-r:逆序排序
-f:忽略大小写常与-u结合使用
-n:按数值大小排序
-t:指定分隔符,默认是空格
-k:按照指定的字段范围
-u:移除重复的行
sort将文件的每一行作为一个单位,相互比较,比较原则是从首字符向后,依次按ASCII码值进行比较,最后将他们按升序输出。
1 )准备素材
# cat facebook.txt
google 110 5000
baidu 100 5000
gab 200 200
guge 50 3000
sohu 100 4500
# sort facebook.txt
baidu 100 5000
gab 200 200
google 110 5000
guge 50 3000
sohu 100 4500
# sort -n facebook.txt
baidu 100 5000
gab 200 200
google 110 5000
guge 50 3000
sohu 100 4500
# sort -r facebook.txt
sohu 100 4500
guge 50 3000
google 110 5000
gab 200 200
baidu 100 5000
第一个域是公司名称,第二个域是公司人数,第三个域是员工平均工资。
2 )我想让facebook.txt按照公司人数排序
# sort -t ' ' -k 2 -nfacebook.txt
guge 50 3000
baidu 100 5000
sohu 100 4500
google 110 5000
gab 200 200
但是,此处出现了问题,那就是baidu和sohu的公司人数相同,都是100人,这个时候怎么办呢?
按照默认规矩,是从第一个域开始进行升序排序,因此baidu排在了sohu前面。
但是这里如果不加-n:
# sort-t ' ' -k 2 facebook.txt
sohu 100 4500
baidu 100 5000
google 110 5000
gab 200 200
guge 50 3000
3 )我想让facebook.txt按照公司人数排序 ,人数相同的按照员工平均工资升序排序:
# sort -n -t ' ' -k 2 -k 3 facebook.txt
guge 50 3000
sohu 100 4500
baidu 100 5000
google 110 5000
gab 200 200
看,我们加了一个-k2 -k3就解决了问题。对滴,sort支持这种设定,就是说设定域排序的优先级,先以第2个域进行排序,如果相同,再以第3个域进行排序
# sort -n -t ' ' -k 2 -k 1 facebook.txt
guge 50 3000
baidu 100 5000
sohu 100 4500
google 110 5000
gab 200 200
4 )我想让facebook.txt按照员工工资降序排序,如果员工人数相同的,则按照公司人数升序排序
# sort -n -t ' ' -k 3 -r -k 2 facebook.txt
google 110 5000
baidu 100 5000
sohu 100 4500
guge 50 3000
gab 200 200
# sort -n -t ' ' -k 3r -k 2 facebook.txt #r和区域写在一起
baidu 100 5000
google 110 5000
sohu 100 4500
guge 50 3000
gab 200 200
5 )-k选项的具体语法格式
要继续往下深入的话,就不得不来点理论知识。你需要了解-k选项的语法格式,如下:
[ FStart [ .CStart ] ] [ Modifier ] [ , [ FEnd [ .CEnd ] ][ Modifier ] ]
这个语法格式可以被其中的逗号(“,”)分为两大部分,Start部分和End部分,注意:Start和End跨域没有意义
先给你灌输一个思想,那就是“如果不设定End部分,那么就认为End被设定为行尾”。这个概念很重要的,但往往你不会重视它。
Start部分也由三部分组成,其中的Modifier部分就是我们之前说过的类似n和r的选项部分。我们重点说说Start部分的FStart和C.Start。
C.Start也是可以省略的,省略的话就表示从本域的开头部分开始。之前例子中的-k 2和-k 3就是省略了C.Start的例子喽。
FStart.CStart,其中FStart就是表示使用的域,而CStart则表示在FStart域中从第几个字符开始算“排序首字符”。
同理,在End部分中,你可以设定FEnd.CEnd,如果你省略.CEnd,则表示结尾到“域尾直到行尾”,即本域的最后一个字符。或者,如果你将CEnd设定为0(零),也是表示结尾到“域尾”。
6)从公司英文名称的第二个字母开始进行排序:
# cat facebook.txt
google 110 5000
baidu 100 5000
gab 200 200
guge 50 3000
sohu 100 4500
# sort -t ' ' -k 1.2 facebook.txt
gab 200 200
baidu 100 5000
sohu 100 4500
google 110 5000
guge 50 3000
看,我们使用了-k 1.2,这就表示对第一个域的第二个字符开始到本域的最后一个字符为止的字符串进行排序。你会发现baidu因为第二个字母是a而名列榜首。sohu和 google第二个字符都是o,但sohu的h在google的o前面,所以两者分别排在第二和第三。guge只能屈居第四了。
# sort -t' ' -k1.2 555test
faidu 100 5000
cb aa 30 c
bb aa 30 x
ab ba 30 b
sohu 100 4500
eoogle 100 6000
guge 50 3000
# sort -nt' ' -k1.2 555test
ab ba 30 b
bb aa 30 x
cb aa 30 c
eoogle 100 6000
faidu 100 5000
guge 50 3000
sohu 100 4500
#
只针对公司英文名称的第二个字母进行排序,如果相同的按照员工工资进行降序排序:
# sort -t ' ' -k 1.2,1.2 -k 3,3nr facebook.txt
baidu 100 5000
gab 200 200
google 110 5000
sohu 100 4500
guge 50 3000
由于只对第二个字母进行排序,所以我们使用了-k 1.2,1.2的表示方式,表示我们“只”对第二个字母进行排序。(如果你问“我使用-k 1.2怎么不行?”,当然不行,因为你省略了End部分,这就意味着你将对从第二个字母起到本域最后一个字符为止的字符串进行排序)。对于员工工资进行排 序,我们也使用了-k 3,3,这是最准确的表述,表示我们“只”对本域进行排序,因为如果你省略了后面的3,就变成了我们“对第3个域开始到最后一个域位置的内容进行排序” 了。
4、去重复行:uniq
uniq [选项]... [文件]
说明:这个命令读取输入文件,并比较相邻的行,删除相同且相邻的的重复行
-i:忽略大小写
-d:仅显示重复的行
-u:仅显示不重复的行
-c:去重后显示每行出现了的次数(相同且相邻才是重复)
# cat uniq.txt
abc
123
123
abc
ABC
123
# uniq uniq.txt
abc
123
abc
ABC
123
# uniq -i uniq.txt
abc
123
abc
123
# uniq -d uniq.txt
123
# uniq -di uniq.txt
123
abc
# uniq -u uniq.txt
abc
abc
ABC
123
# uniq -c uniq.txt
1 abc
2 123
1 abc
1 ABC
1 123
因为uniq是删除去除连续相同的行,所有uniq一般和sort命令一起使用,也就是先将文件使用sort排序(这样重复的内容就能显示在连续的几行中),然后再使用uniq删除掉重复的行
# sort uniq.txt|uniq -c
3 123
2 abc
1 ABC
5、文本替换:tr
tr ... SET1 #后面不能带参数
把输出数据中的在SET1中的每个字符对应地替换为SET2的每个字符
-d, --delete删除匹配SET1的内容,并不作替换
# cat /etc/issue
CentOS release 6.5 (Final)
Kernel \r on an \m
# tr 'aen' 'x'
页:
[1]