您的位置:首页 > 运维架构 > Shell

shell学习笔记二--工具 推荐

2009-09-29 16:33 363 查看
http://licong.blog.51cto.com/542131/205615《shell学习笔记一--总括》中我们粗略介绍了一下sehll的六大功能,本篇我们来详细讨论一下功能一:执行程序。上篇文章中我们较为详细的介绍了一下sehll解释命令行的规则和顺序,本篇我们将详细描述sehll中经常用到的一些程序(也称命令、工具)。当然,其中会参插很多前面讲过的。Shell脚本中经常用到的工具有cut、tr、grep、sort、uniq、re、sed、awk等。Re不是一个程序,我们认为他是shell中一个重量级的工具。对这些工具的使用越精通,编写shell脚本解决问题就越容易!re/sed/awk是shell中最难的一部分内容(至少笔者这么认为),在我的其他文章中专门对他们进行过讨论,所以这里将不做介绍。 一、[/b]cut[/b] 如果要从数据文件或者命令的输出中截取(也就是剪出)各种各样的数据域,cut命令都会派上用场,命令的一般格式为cut –cchars file其中,chars指定想从文件的每一行中截取哪些文字。这可以是一个数字,如-c5就是把第5个字符截取出来;用逗号分隔的数值列表,如-c1,13,50把第1、13和50个字符截取出来;或用破折号分隔的数值范围,如-c20-50截取出第20到50之间的字符,包括他们自己。如果要把到行尾的字符全部截取出来,可以用数值范围,缺掉第2个参数,因此cut –c5- data把data文件每一行中从第5个字符到行尾的内容全部截取出来了,并把结果写入标准输出(屏幕)。如果不指定file参数,cut从标准输入(通常是键盘)读取输入,这以为着可以把cut命令用作管道线中的过滤器。我们再看who命令的输出:$whoroot tty2 2009-08-17 16:59root pts/0 2009-09-17 23:50 (192.168.1.130)stu1 pts/2 2009-09-27 15:26 (192.168.1.130)$who | cut –c1-8root 2009-08-17 16:59root 2009-09-17 23:50 (192.168.1.130)stu1 2009-09-27 15:26 (192.168.1.130)$选项-c1-8,18-意思是截取行中的第1到8个字符(用户名)和第18到行尾的字符(登陆时间)。-d[/b]和-f[/b]选项[/b]当数据文件或命令的输出不像who那样给出整齐的格式,那么-c选项就不那么好用了。例如,看一下文件/etc/passwd:$cat /etc/passwdmysql:x:501:501::/home/mysql:/bin/bashwww:x:48:48::/home/www:/bin/bashldap:x:55:55:LDAPUser:/var/lib/ldap:/bin/falsetest:x:502:502::/home/test:/bin/bashstu1:x:503:503::/home/stu1:/bin/bash$该文件的第一个冒号之前的字符都是系统用户名,我们想要截取这些用户名应该怎么办呢?因为每个名字的长度都可能不一样,所以-c在这里不能很好得完成任务了。但是这个文件有一个特点,它的各个字段都用冒号分隔。尽管不同行之间的每个字段长度都不一样,但可以数冒号来得到各行中的同一字段。这时候我们需要-d和-f,命令格式变为:cut –ddchar –ffieldsfile其中,dchar是数据中分隔各字段的分隔符,fields表示要从文件file中截取出来的字段。字段编号从1开始,而且格式和-c指定字符是一样的(如-f1-3,8-)。所以要从/etc/passwd中截取出系统中的用户名,可以键入以下命令:$cut –d: -f1/etc/passwdmysqwwwldapteststu1$ 二、tr[/b]过滤器tr用来转换来自标准输入的字符。Tr命令的一般格式为tr from-charsto-chars其中from-chars和to-chars是一个或多个字符。所输入的任何字符,如果在from-chars中,它就被转换成to-chars中对应的字符。转换的结果写入标准输出。在tr最简单的格式中,它可以把一个字符转换成另一个字符。$tr m M </etc/passwdMysql:x:501:501::/hoMe/Mysql:/bin/bashwww:x:48:48::/hoMe/www:/bin/bashldap:x:55:55:LDAPUser:/var/lib/ldap:/bin/falsetest:x:502:502::/hoMe/test:/bin/bashstu1:x:503:503::/hoMe/stu1:/bin/bash$/etc/passwd文件中的小写m都被转换成大写M了。$cut –d: -f1,6/etc/passwd | tr : ‘ ‘mysql/home/mysqlwww /home/wwwldap/var/lib/ldaptest /home/teststu1 /home/stu1$cut先截取第1和6字段,然后tr将冒号替换成空格。$cut –d: -f1,6/etc/passwd | tr ‘[a-z]’ ‘[A-Z] ‘MYSQL:/HOME/MYSQLWWW:/HOME/WWWLDAP:/VAR/LIB/LDAPTEST:/HOME/TESTSTU1:/HOME/STU1$cut先截取第1和6字段,然后tr将所有小写字母转换为大写。-s[/b]选项[/b]tr命令的-s选项用来压缩to-chars中重复的字符。换句话说,如果转换完成后,有to-chars中的某个连续字符重复出现,则这些连续的相同字符将被替换为一个字符。$ cut –d: -f1,6/etc/passwd | tr –s mw MWMysql:/hoMe/MysqlW:/hoMe/Wldap:/var/lib/ldaptest:/hoMe/teststu1:/hoMe/stu1$tr将m和w分别替换成M和W,并且将连续的M或W替换成一个字符,所以第二行的WWW变成了单个W。$cat data1 2 34 5 6$tr –s ‘ ‘ ‘ ‘< data1 2 34 5 6$带-s参数的tr将data文件每行的多个空格压缩为一个,这里from-chars和to-chars同为单个空格。处理的顺序是先替换后压缩,不管替换有没有产生变化。该命令和sed ‘s/ */ /g’是同样的效果,而且和sed一样,tr、cut均不改变源文件(只是对文件的一个拷贝进行处理)-d[/b]选项[/b]tr也可以删除掉输入流中的字符,其一般格式为tr –dfrom-chars 任何列在from-chars中的字符都会被从标准输入中删除。$ tr -d ‘ ‘< data123456$tr –d删除data文件中的所有空格,结果写入标准输出(屏幕)。该命令和sed ‘s/ //g’等效。tr只能对个别字符操作,如果要转换多个字母的组合,就必须用其他程序,如sed。 三、grep[/b]grep命令可以从一个或者多个文件中搜索特定的字符串模式,其一般格式为grep patternfiles每个文件中符合模式pattern的字符串所在的行都将显示在终端上。如果给grep指定了多个文件,会在每一行的前面显示文件名,这样可以识别从中找到该模式的文件。还是以前面的 /etc/passwd文件为例:$cat /etc/passwdmysql:x:501:501::/home/mysql:/bin/bashwww:x:48:48::/home/www:/bin/bashldap:x:55:55:LDAPUser:/var/lib/ldap:/bin/falsetest:x:502:502::/home/test:/bin/bashstu1:x:503:503::/home/stu1:/bin/bash$grep www/etc/passwdwww:x:48:48::/home/www:/bin/bash$该输出表明,文件/etc/passwd中有一行包含字符串www。如果在给定的文件中没有符合该迷失的字符串,grep命令就什么也不显示:$grep tom/etc/passwd$如果另一个文件data的内容如下:$cat datawww in datatom in datajerry in data$在在/etc/passwd和data两个文件中搜索www的结果如下:$ grep www/etc/passwd data/etc/passwd:www:x:48:48::/home/www:/bin/bashdata:www indata$结果,除了显示包含www的行外,还显示了他们所在的文件名。命令格式中的pattern通常是一个正则表达式re(www也是一个re),关于re的介绍不在本文给出,请参考其他文章。-v[/b]选项[/b]有时用户所关心的不是包含指定模式的行,而是不包含的那些行。grep处理这个问题很容易:用-v选项。下面我们来查找/etc/passwd中不包含www的行:$grep –v www/etc/passwdmysql:x:501:501::/home/mysql:/bin/bashldap:x:55:55:LDAPUser:/var/lib/ldap:/bin/falsetest:x:502:502::/home/test:/bin/bashstu1:x:503:503::/home/stu1:/bin/bash结果中除了包含www的那行外,其他所有行都被显示了出来。-l[/b]选项[/b]有时,用户可能不关心包含一个模式的具体行,而只想知道包含该模式的文件名。下面的例子给出了简单的方法:$ grep –l www/etc/passwd data file/etc/passwddata$其中,只有file中没有包含www的行,于是结果显示了包含www的文件名。因为grep很方便的把每个文件显示为一行,我们可以在命令后面通过管道把输出输送给wc–l的输入,以获得包含指定模式的文件的个数。$ grep –l www/etc/passwd data file | wc –l2-n[/b]选项[/b]如果grep用了-n选项,文件中符合指定模式的每一行都将加上该行在文件中相对行号。下面的例子告诉我们如何查明文件中包含模式的确切行号:$grep –n www/etc/passwd2:www:x:48:48::/home/www:/bin/bash结果表明,包含www的行位于/etc/passwd的第2行。 四、sort[/b]sort用于对指定的文件中的行进行排序,其基本格式为:sort file(s)将文件file(s)中的行排序,若未指定,则排序标准输入(键盘输入)。$cat namesLucyTonyFredTony$sort有许多选项,可以让排序操作非常灵活。下面我们只介绍其中一部分选项。-u[/b]选项[/b]-u选项告诉sort命令,在输出结果中去除重复的行:$sort namesFredLucyTonyTony$sort –u namesFredLucyTony$可以看出,包含Tony的重复行从输出中被去掉了。-r[/b]选项[/b]用-r选项颠倒排序顺序:$sort –r namesTonyTonyLucyFred$-o[/b]选项[/b]默认情况下,sort把输出结果写入标准输出。要把结果写入文件,可以用输出重定向:$sort names> sorted_names$另一种方法是用-o选项指定输出文件,只要在-o之后接着写上输出文件名:$sort names -osorted_names$该命令把对文件names排序的结果写入sorted_names。很多时候都会想把一个文件中的各行排序,然后把排好序的结果写回原来的文件,键入$sort names> names$不能成功,它将以破坏文件而告终。然而,采用-o选项时,却可以给输出文件指定和输入文件相同的名字:$sort names -onames$cat namesFredLucyTonyTony原来的文件顺序被排好了,并且不会有任何错误,这个-o确实蛮好的。-n[/b]选项[/b]sort默认是按照ASCII编码的顺序来进行排序的,如果要按照数学方式来排序,该怎么做呢?看下面的例子:$cat data1 11 www-3 13 jerry2 12 tom$sort data1 11 www2 12 tom-3 13 jerry$sort –n data-3 13 jerry1 11 www2 12 tom可以看到,-n参数按照数字大小来进行排序了。跳过字段[/b]接着上面的例子,如果想要以第二列数字来进行排序该怎么办呢?看下面的做法:$sort +1n data1 11 www2 12 tom-3 13 jerry$结果是以第二列数字排序的,+1代表跳过第一字段。注意,不是所有的sort都支持+这个选项,这和你的系统或者sort版本有关。$sort +1n datasort: openfailed: +1n: No such file or directory某些系统运行该命令将得到如上的错误信息。-t[/b]选项[/b]$cat /etc/passwdmysql:x:501:501::/home/mysql:/bin/bashwww:x:48:48::/home/www:/bin/bashldap:x:55:55:LDAPUser:/var/lib/ldap:/bin/falsetest:x:502:502::/home/test:/bin/bashstu1:x:503:503::/home/stu1:/bin/bash$如果想要以冒号作为分隔符,按照第三列数字(用户id)来对/etc/passwd进行排序,应该怎么做呢。是用下面这个命令吗?$sort +2n/etc/passwd错了,因为跳过字段时,sort默认是以空格或者制表符(tab)来分隔字段的。这里我们需要用-t参数,改变sort默认的字段分隔符:$sort +2n –t:/etc/passwdwww:x:48[/b]:48::/home/www:/bin/bashldap:x:55[/b]:55:LDAPUser:/var/lib/ldap:/bin/falsemysql:x:501[/b]:501::/home/mysql:/bin/bashtest:x:502[/b]:502::/home/test:/bin/bashstu1:x:503[/b]:503::/home/stu1:/bin/bash$这里我们把第三字段用黑体标注了起来,方便检验排序的正确性。 四、uniq[/b]如果要在文件中查找重复的行,uniq命令会很管用,该命令一般格式为uniq in_file out_file该格式中,uniq把in_file复制到out_file,处理过程中,去掉重复的行。uniq对重复行的定义是完全相同的连续行。如果不指定第二个参数out_file,结果就写入标准输出;如果in_file也没有指定,uniq就成了一个过滤器,从标准输入读入输入。下面有几个例子示意uniq如何工作。$cat namesLucyTonyFredTony$可以看出,文件中Tony出现了两次,可以用uniq来删除这种重复的行:$uniq namesLucyTonyFredTony$奇怪,输出中Tony仍然出现了两次,unqi没有用吗?对了,前面说了,uniq对重复行的定义是完全相同的连续行。而这里的两行Tony被Fred分开了,uniq自然不会改变他们。再看下面是怎么处理的:$sort names | uniqFredLucyTony$sort先对文件进行了排序,这样两行Tony就连续了,这次uniq就派上用场了。(想想带-u选项的sort命令,完成的就是这个功能)-d[/b]选项[/b]很多时候,用户所关心的是找出文件中有哪些重复行。uniq的-d选项就是这个作用:它告诉uniq把文件中的重复行写入out_file(或标准输出),不管他们在文件中连续出现多少次,这样的连续行只写一次。$sort names | uniq -dTony和前面一样,sort先对文件排序,然后uniq –d找到重复的连续行,然后只显示一行。下面的命令可以用来检查系统中是否有相同的帐户:$sort /etc/passwd | uniq –d$结果将显示属性完全相同的两个unix帐户,如果只是想要找出同名的帐户呢,我们需要截取/etc/passwd文件的第一字段来进行操作:$sort /etc/passwd | cut –d: -f1 | uniq –dharrytom$上面的结果表明,系统中至少有2个harry和2个tom帐户。-c[/b]选项[/b]带-c选项的uniq删除重复行的同时,显示每行出现的次数。$sort names | uniq -c 1 Fred 1 Lucy 2 Tony$ 本文详细介绍了工具cut、tr、grep、sort、uniq的用法。re、sed、awk在笔者以下几篇文章中分别加以讨论:http://licong.blog.51cto.com/542131/200431《正则表达式详解》http://licong.blog.51cto.com/542131/152541《sed学习笔记》http://licong.blog.51cto.com/542131/204226《sed学习笔记二--高级命令》http://licong.blog.51cto.com/542131/151976《awk学习笔记》再重复一次,以上工具掌握得越灵活,编写shell脚本就越容易。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  linux 职场 shell 休闲 bash