Shell脚本学习指南
使用《Shell脚本学习指南》一书,学习Shell编程,为运维积累一些基础知识。
Shell学习工具
所使用的的学习工具:Windows 7、VMware Workstation、RHEL 7/Ubuntu 16.04、Vim
软件工具的原则
一次做好一件事
一次只做好一件事的程序在设计、编写、调试、维护,以及生成文件都会容易的多。功能更专一更专业。
处理文本行,不要处理二进制数据
文本行是UNIX的通用格式。
使用正则表达式
强大的文本处理机制,可简化编写命令脚本的工作。
默认使用标准输入/输出
使用标准输入出可轻松让它们称为数据过滤器(filter)。
避免喋喋不休
“在工具程序的世界里,没有消息就会好消息”。
输出格式必须与可接受的输入一致
专业的工具程序认为遵循某种格式的输入数据所产生的输出数据也应遵循与输入数据一致的规则。这么做的好处是,容易将一个程序的执行结果交给另一个程序处理。
让工具去做困难的部分
- 构建特定工具前,先想想。
在构建自己的工具之前先想一想这个问题是否具有一般性,从而制作出满足更多人使用的工具。
脚本编程语言与编译型的差异
编译型语言:好处是高效,缺点是多半运行在底层,所处理的是字节、整数、浮点数或是其他机器层级的对象。
脚本语言:通常是解释型的语言。由解释器(interpreter)读入程序代码,并将其转换成内部的形式,再执行。脚本程序的好处是,它们多半运行在比编译语言还高的层级,能够轻易处理文件与目录之类的对象;缺点是效率通常不如编译型语言,但是现代计算机硬件水平,使得执行效率问题只能放在次要。
常见的脚本编程语言:awk、Perl、Python、Ruby、Shell…
Shell优点
- 简单性
- 可移植性
- 开发容易
Shell的重要基本元素
- 命令与参数
- 变量
- echo输出
- printf输出
I/O重定向
重定向:
以<改变标准输入:program < file可将program的标准输入改为file
以>改变标准输出:program > file可将program的标准输出改为file。在目的文件不存在时,会新建一个。当目的文件存在时,它会被覆盖掉,原始数据会丢失。
以>>附加到文件:program >> file可将program的标准输出附加到file的结尾处。在目的文件不存在时,会新建一个。当目的文件存在时,不会直接覆盖掉文件,而是将程序所产生的数据附加到文件的结尾处。
管道:
以 | 建立管道:program1 | program2可将program的标准输出修改为program2的标准输入。
虽然<和>可将输入与输出连接到文件,不过管道(pipeline)可把两个以上执行中的程序衔接在一起。第一个程序的标准输出可以变成第二个程序的标准输入。这么做的好处是,管道可以使得执行速率比使用临时文件的程序快上十倍。
构造管道时,应该试着让每个阶段的数据量变得更少,这样会提升脚本的整体性能。
特殊文件:/dev/null与/dev/tty:
/dev/null:位桶(bit bucket),传送到此文件的数据都会被系统丢掉。也就是说,当程序将数据写到此文件时,会认为它已完成写入数据的操作,但实际上什么事都没有做。如果你需要的是命令的退出状态,而非它的输出,此功能会很有用。基本命令查找
Shell会沿着查找路径$PATH来寻找命令。$PATH是一个以冒号分隔开的目录列表,可以在列表所指定的目录下找到所要执行的命令。所找到的命令可能是编译后的可执行文件,也可能是shell脚本,从用户的角度来看,两者并无不同。
使用“echo $PATH”可以查看本系统的路径。
bin文件,即是用来保存可执行文件的,bin是Binary的缩写。
建立自己的bin目录,并将它加入$PATH中的列表。
cd 切换到home目录
mkdir bin 建立个人bi内目录
mv nusers bin 将脚本移入该目录
PATH=$PATH:$HOME/bin 将个人的bin目录附加到PATH
nusers 执行bin目录下的命令
6 执行结果。
每次登录时,shell都将读取.profile文件,所以在.profile文件中将bin目录加入$PATH,即可让修改永久生效。
$PATH中的空目录,表示当前项目。空项目位于位于路径值中间时,可以用两个连续的冒号进行表示。如果将冒号位于最前端或尾端,可以分别表示查找时最先查找或最后查找当前目录。
但是,在路径中不应该出现当前目录,这样会出现安全问题,或者移植性等问题。
访问Shell脚本的参数
- 位置参数
Shell脚本的命令行参数。在Shell函数里,它们同时也可以是函数的参数。各参数都由整数来命名,不超过9,超过9使用花括号括起来。
$1、$2...$9、${10}
简单的执行跟踪
- 使用sh命令
在每个被执行的命令前加上一个“+”和一个“ ”(空格)
sh -x nusers 打开执行跟踪功能
> + who 被跟踪的命令
> + wc -l 被跟踪的命令
> 1实际的输出
在脚本里可以使用set -x
打开执行跟踪的功能,其后执行的命令都会被显示出来;使用set +x
关闭执行跟踪功能,其后执行的命令不会被跟踪,只是显示命令执行的结果。
查找文本
简单的grep
who | grep -F skl
:[-F]参数是指定匹配固定(fixed)字符串。 可默认省略.BRE(基本正则表达式)
正则表达式是一种表达方式,让你可以查找匹配特定准则的文本。
从根本上看,正则表达式是由两个基本组成部分所建立:一般字符和特殊字符。
一般字符:任何没有特殊意义的字符。
特殊字符:也称为元字符(metacharacter),在某些情况下,特殊字符也可视为一般字符。匹配单个字符
一般字符:包括所有文字和数字字符、绝大多数的空白(whitespace)字符以及标点符号字符。一般字符所表示的就是它们自己(严格对应)。
转义的meta字符:当需要匹配meta字符本身时,需要使用一个反斜杠\
进行转义,但若将反斜杠置于一般字符前,通常会被忽略。
以.
(点号)meta字符:意即“任一字符”,它多半与其他meta字符搭配使用,这一结合允许匹配多个字符。
方括号表达式:最简单的方括号表达式是直接将字符列表放在方括号里。例如:[aeiouy]
表示的就是就是所有小写元音字母,c[aoiouy]t
匹配与cat、cot、cut、cit、cet、cyt。在方括号中使用^
放在字首表示取反的意思,也就是不在方括号列表里的任意字符。方括号中排序、等价、字符集:
排序:是指给予组成的项目排列顺序的操作。一个POSIX的排序元素由当前locale中的元素名称组成,并由[.与.]
括起来。例如要匹配ch
连续字符,顺序不能改变,则应构造成[.ch.]
。
等价:用来让不同的字符在匹配时视为相同字符。使用[=与=]
。例如在法语元音中é和è需要使用[=e=]
进行匹配。
字符集:表示字符的类别,例如数字、小写、大写字母、标点符号、空白等。这些类别名定义于[:与:]
之间,以下是POSIX字符集:
在方括号表达式中,其他的meta字符都会失去其特殊含义。所以[*\.]
匹配于字面的星号、反斜杠、以及句点。要让]
进入该集合,应该将它放在列表的最前面[]*\.]
、要让-
(减号)进入集合,也将放在列表的最前端[-*\.]
。若需要将]
和-
两者进入集合,则应这样写[]*\.-]
。后向引用
匹配于正则表达式匹配的先前的部分。
步骤:
1.将子表达式包围在\(
和\)
中,单个模式最对可以包含至多9个子表达式,且可为嵌套结构。
2.在同一模式之后使用\digit
,digit指的是介于1至9的数字。指的是“匹配于第n个先前方括号内子表达式匹配成功的字符”。
后续将进行补充单个表达式匹配多个字符
1.将需要匹配的字符全部列出来,或者使用方括号的字符集结构,例如
[[:upper:]][[:lower:]]
匹配任意一个大写字母字符后面紧接着一个小写字母字符。
2.使用*
匹配0个或多个前面的单个字符。
3.*修饰符没有匹配字符数量的限制,解决这一问题可以使用区间表达式解决。区间表达式是将一个或两个数字,放在\{
与\}
之间,有三种变化:
\{n\}
:前置正则表达式所得结果重现n次;
\{n,\}
:前置正则表达式所得结果重现至少n次;
\{n,m\}
:前置正则表达式所得结果重现n至m次。
例如:a\{5\}
重现5个a;q\{10,42\}
重现10至42个q。文本匹配锚点
锚点:其用途是在限制正则表达式匹配时,针对要被匹配字符串的开始或结尾处进行匹配。有两个:脱字符号(^)和货币符号($),
^
(在此处的用法与方括号表达式中的完全不同)
使用脱字符^
,表示匹配以(模式)开头的字符串;使用货币符号$
,表示匹配以(模式)$结尾的字符串。
^
与$
同时使用,则表示将括起来的正则表达式匹配整个字符串(或行)。
^$
用来匹配空的(empty)字符串或行列。运算符优先级
BRE的运算符优先级:
ERE(扩展正则表达式)
管道
“命令一个个串联起来完成任务,而每一个又都完成步骤性的一个重要任务”
Unix工具使用原则:想清楚这个问题该如何划分成更简单的工作,每个部分是不是已有现成的工具能解决,还是你可以写上几行shelll程序或者使用脚本语言就能拿上解决。
未完,待续……