红帽秘笈,第二十二章用bash写脚本

本章主要介绍如何使用bash写脚本。
了解通配符
了解变量
了解返回值和数值运算
数值的对比
判断语句
循环语句
grep的用法是“grep 关键字 file”,意思是从file中过滤出含有关键字的行。
例如,grep root /var/log/messages,意思是从/var/log/messages 中过滤出含有root
的行。这里很明确的是过滤含有“root”的行。
如果想在/var/log/messages 中过滤出含有IP地址的行呢?IP地址就是一类字符,例如,
1.1.1.1是一个IP,192.168.26.100也是一个IP,那么用什么能表示出来这一类字符呢?
不管是通配符还是正则表达式,都是为了模糊匹配,为了匹配某一类内容,而不是具体的
某个关键字。通配符一般用在shell语言中,正则表达式一般用在其他语言中。
不管是通配符还是正则表达式,主要是理解它们的元字符,然后用元字符来组合成我们想
要的那一类字符,本章主要讲解通配符的使用。
像我们平时说的张某某,这个某就是一个元字符,不是一个定值。指的是姓张,名字含有
2个字。张某某可能匹配到张二狗,也可能匹配到张阿猫,但是无法匹配到李阿三,也匹配
不了张三,因为张某某匹配的是姓名为3个字的,但是张三这个姓名只有2个字。
如果说有一个人姓“张”名“某”,那么需要匹配“张某”这个人,而不是要匹配张三、
张四,可以用张\某,某前加个“\”表示转义的意思。
通配符一般用在shell语言中,通配符中常见的元字符如下。
(1)[]:匹配一个字符,匹配的是出现在中括号中的字符。
(2)[abc]:匹配一个字符,且只能是a或b或c。
(3)[a-z]:“-”有特殊意义,表示“到”的意思,这里表示a~z,即匹配任一字母。
(4)[0-9]:表示匹配任一数字。
如果想去除含有特殊意义的字符,前面加“\”表示转义,即去除此字符的特殊意义。
(5)[a\-z]:这里的“-”就没有“到”的意思了,匹配的是“a”或“-”或“z”这三个
中的一个。
如果想表示“除了”的意思,则在第一个中括号后面加“!”或“^”。
(6)[!a-z]、[^a-z]:表示除字母外的其他字符。
(7)?:表示一个任意字符,这里强调是一个,不是0个也不是多个,但不能匹配表示隐藏
文件的点。
(8)*:表示任意多个任意字符,可以是0个,也可以是1个或多个,但不能匹配表示隐藏
文件的点。
练习:先创建目录xx并在目录中创建如下几个测试文件,命令如下。

 

 找出首字符是字母、第二个字符是数字的文件,命令如下。

[root@localhost xx]# ls [a-z][0-9]*

找出首字符是字母、第二个字符不是数字的文件,命令如下。  

找出首字符不是字母、第二个字符不是数字的文件,命令如下。

 

 

可以看到,找出来的文件完全符合我们的需求。下面找出首字符是大写字母、第二个字符
是非数字的文件,命令如下。

 

 

可以看到,首字符是大写字母的文件列出来了,首字符是小写字母的文件有的列出来了,
有的没有列出来,所以[a-z]或[A-Z]有时并不精确。如果要更精确,可以用如下元字符。
(1)[[:upper:]]:纯大写。
(2)[[:lower:]]:小写。
(3)[[:alpha:]]:字母。 (4)[[:alnum:]:字母和数字。
(5)[[:digit:]]:数字。
列出首字符是小写字母、第二个字符是数字的文件,命令如下。
[root@localhost xx]# ls [[:lower:]][0-9]*

 列出首字符是大写字母、第二个字符是数字或字母的文件,命令如下。

 如果想在yum 源中列出所有以 vsftpd开头的包,可以用如下命令。

[root@localhost xx]# yum list vsftpd*

此处显示没有匹配的包,为什么呢?因为yum是 bash的一个子进程,vsftpd在 bash中首
先被解析成了vsftpdxxx,然后再经过yum。所以,本质上执行的是yum list vsftpdxx命 令,而yum源中是没有vsftpdxxx 这个包的,所以报错。
为了防止 bash 对这里的*进行解析,可以加上转义符“\”,所以下面的命令是正确的。

 [root@localhost ~]# yum list vsftpd\*

定义变量有以下几点需要注意。
(1)变量名可以包含_、数字、大小写字母,但不能以数字开头。
(2)“=”两边不要有空格。
(3)“值”如果含有空格,要使用单引号''或双引号""引起来。
(4)定义变量时,变量名前是不需要加$的,引用变量时需要在变量名前加$。
本章实验都放在~/yy中练习,命令如下。

 

下面开始练习定义变量,命令如下。  

 

 这里定义变量不正确,因为变量名不能以数字开头,命令如下。

 

这里正确地定义了一个变量。
在使用本地变量时,变量名前需要加$,命令如下。

本地变量的特点是只能影响当前shell,不能影响子shell。

 

当前shell的PID是3552。下面打开一个子shell。

 

可以看到,没有aa变量。

 

再次退回到原来的bash,又有了aa变量,情形如图
定义变量除刚才显式的定义外,还可以使用如下两
种方法。
方法1:把一个命令的结果赋值给一个变量,这个
变量要使用$()括起来,或者用反引号“引起来。这里是反引号,与波浪号~是同--个键,不是
单引号。
例如,定义一个名称是ip的变量,对应的值是ens160的IP

 

当遇到read命令时,系统会等待用户输入,用户所输入的值会赋值给read后面的变量,
命令如下。

 

当执行read这条命令时,系统会提示用户输人一些内容,所输入的内容会赋值给aa变
量。这里我们输入的是 tom,所以打印aa变量时,看到的值是tom。
这样的用法比较适合写需要和用户交互的脚本。、
定义环境变量的注意点和本地变量是一样的。在定义环境变量时,前面加上export 即可,
命令如下。

或者先定义为本地变量,然后再通过export转变为环境变量,命令如下。

 

要想查看所有的环境变量,可以执行env命令。
环境变量的特点是可以影响子shell,这里强调的是子shell,不能影响父shell。

 

 

打开一个子shell,PID为3552,里面可以看到bb变量的值,说明环境变量已经影响到
子shell 了。
有一个很重要的环境变量PATH,当我们执行命令时,一定要指定这个命令的路径,如果
没有写路径,则会到PATH变量所指定的路径中进行查询。先查看当前用户的PATH变量,命
令如下。

 

PATH变量由多个目录组成,每个目录之间用冒号“:”分隔,我们把写好的脚本放在
PATH变量指定的目录中之后,运行此脚本时就不需要指定路径了。
查看tom用户的PATH变量,命令如下。

 

给这个脚本加上可执行权限,并加参数运行,命令如下。

 

 例1:写一个带参数的脚本,内容如下。

 

运行这个脚本时,共指定了3个参数:tom、bob、mary,它们分别赋值给了
$1、$2、$3。这里S#被自动赋值为3,因为总共有3个参数,所有的参数被赋值给$*。
例2:运行如下命令。

查看此命令的第1个和第9个参数,命令如下。

 

 第1个参数是a,第9个参数是i。下面查看第10个参数,命令如下。

第9个参数是i,那么第10个参数应该是j才对,这里显示为a0,为什么呢?因为这里先把
$10当成了$1+0,$1的值是a,所以$10的值为a0。
所以,在位置变量中数字超过10时,要用{}括起来,下面的命令才是正确的。

 

 另外,在引用变量时,双引号和单引号是有区别的,直接看一个例子。

 练习:先执行一个 xxx命令,命令如下

 

先执行一个xxx命令,这个命令是错误的命令,$?记录的是刚刚执行过xxx命令的返回值。
所以,查看$?的值是127,是一个非零的值。再次查看$?的值时,却变成了0,因为这个$?
记录的不再是xxx命令的返回值,而是它前面执行过的echo $?命令的返回值。

 逻辑上“否定”的意思也是可以体现出来的。例如,下面的例子。

 这里在/etc/passwd过滤行开头为root的行,结果找到了,所以返回值为0。

 

这里在/etc/passwd过滤行开头为rootxxx的行,结果没有找到,即使语法没有错误,但
是逻辑上有“否定”的意思,所以返回值为非零。
进行数学运算的表达式有$(())、$[]、let等,命令如下。

 其中$(O)和$[]的用法是一样的,如果不用这样的表达式,看如下代码。

 这里并不是计算的2的3次方,而是直接把这4个字符打印出来了。let也可以用于数学运算,命令如下。

 

这里aa的值就是为3。
下面来看不使用let的情况,命令如下。

 

里并没有把aa的值1+2当成数字,而是当成了3个字符:“1”“+”“2”,所以结果显
示的也是1+2。
可以实现定义aa为整数类型,然后再做数学运算,命令如下。

 

 

这里N是一个数字,表示小数点后面保留几位。
计算2/3,小数点后面保留3位,命令如下。

 

这里得到的结果是0.666,整数部分的0没有显示。
计算7/6,小数点后面保留3位,命令如下。

 

数字的比较,主要是比较两个数字谁大谁小,或者是否相同。能用到的比较符有以下几
种。
(1)-eq:相等。
(2)-ne:不相等。
(3)-gt:大于。
(4)-ge:大于等于。
(5)-lt:小于。
(6)-le:小于等于。
做完比较之后,通过返回值来判断比较是否成立。
练习1:判断1等于2,命令如下

 

1是不能等于2的,所以判断不成立,返回值为非零。注意中括号和比较符两边的空格。
练习2:判断1不等于2,命令如下。

 

字符串的比较,一般是比较两个字符串是否相同,用得较多的比较符有以下两种。
(1)==:相同。
(2)!=:不相同。
做完比较之后,通过返回值来判断比较是否成立。
练习1:定义一个变量aa=bdqn,然后做判断,命令如下。

 

()-d:一个目录。
()-l:一个软链接。
()-f:一个普通文件,且要存在。
()-e:不管什么类型的文件,只要存在就算判断成立。
练习1:判断/etc/hosts具备r权限,命令如下
这里判断/etc/hosts具备x权限,但是/etc/hosts不管是u、g还是o都不具备x权限,所以
判断不成立,返回值为非零。
如果做一个否定判断,在前面加上叹号“!”即可。
练习3:判断/etc/hosts没有x权限,命令如下。

 

只有两个判断都为真(返回值为0),整体才为真,只要有一个为假,整体就为假。判断1
如果为假,判断2还有必要执行吗?没有,因为整体已经确定为假了。判断1为真,整体是真
是假在于判断2,所以判断2肯定是要执行的。

 

 

如果while后面的判断成立,则执行do和 done之间的命令,在最后一个命令执行完成之
后,会回头再次判断一下while后面的判断是不是成立。如果不成立,则跳出循环执行done后
面的命令;如果成立,则继续执行do和 done之间的命令,就这样循环下去。
先看一个简单的例子,写一个脚本/opt/sc3.sh,命令如下。
下面写一个脚本,来实时判断vsftpd是否启动,如果没有启动,则将vsftpd启动,命令如
下。
这里写了一个 while循环,可以一直循环下去,循环中先判断vsftpd是否启动,如果启动
了则返回值为0,如果没有启动则返回值为非零。
下面开始根据返回值来进行判断,如果$?不等于0,说明vsftpd没有启动,则启动vsftpd
服务。sleep 1的意思是暂停1秒,这样就实现了每隔1秒来判断一次vsfilpd是否启动。
下面开始测试这个脚本,先把脚本放在后台运行,命令如下。
[root@localhost ~]# /opt/sc4.sh &

 测试当前vsftpd 的状态,命令如下。

[root@localhost ~]# systemctl is-active vsftpd

关闭vsftpd服务之后,再次检测vsftpd 的状态,命令如下。

[root@localhost ~]# systemctl stop vsftpd

 [root@localhost ~]# systemctl is-active vsftpd

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值