Shell学习笔记(二):入门知识和实战篇

变量的数值计算常见命令

(())letexprbc$[],这里只介绍(())expr

(())用法:

如果要执行简单的整数运算,只需将特定的算术表达式用"$(("和"))"括起来即可。shell的算术运算符合常置于"$(("......"))"的语法中。这一语法如同双引号功能,除了内嵌双引号无需转义。

s-6

提示:

1、上面涉及到的参数变量必须为整数,不能是小数(浮点数)或者字符串。后面的bc命令可以进行浮点数运算,但一般较少用到,

2、echo $((a++))echo $((a--))表示先输出a自身的值,然后在进行++ --的运算,echo $((a++))echo $((--a))表示先进行++ --的运算,再输出a自身的值

  • 记忆方法:变量在前,先输出变量值,变量在后,就是先算后输出变量的值。

一个小计算器:

s-7

expr

expr命令既可以用于整数运算,也可以用于相关字符串长度,匹配等的运算处理

例1:(普通运算)

[root@pan shell]# expr 2 + 2
4
[root@pan shell]# expr 2 - 2    
0
[root@pan shell]# expr 2 * 2
expr: syntax error
[root@pan shell]# expr 2 \* 2
4
[root@pan shell]# expr 2 / 2
1
[root@pan shell]# i=5
[root@pan shell]# i=expr $i + 6
[root@pan shell]# echo $i
11

提示:

1、运算符及用于计算的数字左右都至少有一个空格,否则会报错

2、使用乘号时,必须用反斜线屏蔽其特定含义,因为shell可能会误解星号的含义。

例2:(判断字符串是否为整数)

[root@pan shell]# i=5
[root@pan shell]# expr $i + 6 &>/dev/null   #把i和整数相加,&>/dev/null表示不保留任何输出
[root@pan shell]# echo $?      #输出返回值
0    #返回为0,则证明i的值为整数
[root@pan shell]# i=oldboy   #此时赋值一个字符串给i
[root@pan shell]# expr $i + 6 &>/dev/null     #同样把i和整数相加,不保留任何输出
[root@pan shell]# echo $?     #输出返回值
2   #返回为非0,则证明i的值不是整数

例3:(判断文件扩展名)

[root@pan shell]# expr "web.sh" : ".*\.sh" && echo 1||echo 0
6
1
[root@pan shell]# expr "web.f" : ".*\.sh" && echo 1||echo 0
0
0

例4:(判断变量是否为整数)

代码:

s-8

运行过程:

s-9

例5:(判断字符串长度)

[root@pan shell]# chars=seq -s " " 100
[root@pan shell]# echo ${#chars}
291
[root@pan shell]# echo $(expr length "$chars")
291

Shell变量输入

shell变量除了可以直接赋值或脚本传参外,还可以使用read命令从标准输入获得。

【语法格式】

read [参数] [变量名]

【常用参数】

- p prompt:设置提示信息
- t  timeout 设置输入等待的时间,单位默认为秒

例1:

s-10

例2:

s-11

常用的文件测试操作符

文件测试表达式的用法

s-12

特别说明:这些操作符号对于[[ ]]、[ ]、test几乎是通用的,更多操作符请man test

文件测试表达式举例

1)测试文件类型

范例:

[root@xwq ~]# mkdir test   #创建test文件夹
[root@xwq ~]# touch test.txt   #创建test.txt文件
[root@xwq ~]# [ -f test ] && echo 1 || echo 0   #测试test是否为普通文件。
0   #输出为0,证明test非普通文件,因为前面创建的是test目录,因此输出0,下面的结果也是如此。
[root@xwq ~]# [ -f test.txt ] && echo 1 || echo 0
1
[root@xwq ~]# [ -d test ] && echo 1 || echo 0
1

2)测试文件属性

范例:

[root@xwq ~]# ll test.txt
-rw-r--r--  1 root root  0 Jun  9 20:15 test.txt  文件的默认权限是644
[root@xwq ~]# [ -r test.txt ] && echo 1 || echo 0    #测试是否可读
1    #返回结果为1,文件可读
[root@xwq ~]# [ -w test.txt ] && echo 1 || echo 0  #测试文件是否可写
1    #返回结果为1,文件可写
[root@xwq ~]# [ -x test.txt ] && echo 1 || echo 0  #测试文件是否可执行
0   #返回结果为0,文件不可执行
[root@xwq ~]# chmod 001 test.txt   修改test.txt权限位为001
[root@xwq ~]# ll test.txt
---------x 1 root root 0 Jun  9 20:15 test.txt
[root@xwq ~]# [ -w test.txt ] && echo 1 || echo 0
1    #用户权限为没有w,返回结果还是为1?
[root@xwq ~]# echo "echo test" > test.txt   #测试是否可写
[root@xwq ~]# [ -r test.txt ] && echo 1 || echo 0
1   用户权限为没有r,返回结果还是为1?
[root@xwq ~]# cat test.txt
echo test   #确实可读
[root@xwq ~]# ./test.txt
test

提示:测试文件的读、写、执行等属性,不光是根据文件的=属性rwx的标识来判断,还要看当前执行测试的用户是否可以按照对应的权限操作该文件。

3)测试shell变量实例

首先我们先定义file1和file2两个变量,并赋予这两个变量对应的系统文件路径及文件名的值

[root@xwq ~]# file1=/etc/services;file2=/etc/rc.local   #分号隔开两个命令
[root@xwq ~]# echo $file1 $file2
/etc/services /etc/rc.local

测试:

[root@xwq ~]# [ -f "$file1" ] && echo 1 || echo 0   #文件存在且为普通文件,所以为真(1)
1
[root@xwq ~]# [ -d "$file1" ] && echo 1 || echo 0  #是文件而不是目录,所以为假(0)
0
[root@xwq ~]# [ -s "$file1" ] && echo 1 || echo 0  #文件存在且大小不为0,所以为真(1)
1  
[root@xwq ~]# [ -e "$file1" ] && echo 1 || echo 0  #文件存在,所以为真(1)
1

测试时变量的特殊写法及问题

用[ ]测试变量时,如果被测试的变量不加双引号,那么测试结果可能会是不正确的,

例:

[root@xwq ~]# echo $test   #这是一个不存在的变量

[root@xwq ~]# [ -f $test ] && echo 1 || echo 0   #不加引号测试变量。
1   #明明$test变量不存在内容还返回1,逻辑就不对了
[root@xwq ~]# [ -f "$test" ] && echo 1 || echo 0  #加双引号测试
0   #加了双引号就返回0,逻辑就对了

如果是文件实体路径,那么加引号和不加的结果是一样的:

[root@xwq ~]# [ -f "/etc/services" ] && echo 1 || echo 0
1
[root@xwq ~]# [ -f /etc/services ] && echo 1 || echo 0
1

4)写出高效的测试文件

在做测试判断的时候,不一定要按照“前面的操作成功了如何,否则就如何“ 的方法来进行。直接做部分判断,有时看起来更简洁;

例:

[root@xwq ~]# [ -x test.txt ] && echo 1
1  #如果test.txt可执行,则输出1,如果不可执行则不作任何输出
[root@xwq ~]# [ -f /etc ] || echo 0
0  #如果/etc是文件这一点不成立,则输出0;如果成立则不作任何输出

字符串测试操作符

字符串测试操作符的作用包括:比较两个字符串是否相同、测试字符串的长度是否为零、字符串是否为null等。

s-13

特别注意:

1、以上表格中的字符串测试操作符号务必要用""引起来

2、比较符号两端有空格。

字符串测试操作符提示:

1)-n比较字符串长度是否不为零,如果不为零则为真,如:[ -n "$myvar" ]

2)-z比较字符串长度是否等于零,如果等于零则为真,如:[ -z "$myvar" ]

例1:

[root@xwq ~]# [ -n "abc" ] && echo 1 || echo 0   #如果字符串长度不为0,则输出1,否则输出0
1
[root@xwq ~]# test -n "abc" && echo 1 || echo 0   #test的用法同上述[ ]的用法
1
[root@xwq ~]# test -n "" && echo 1 || echo 0
0
[root@xwq ~]# var="yjscloud"     #给变量var赋值yjscloud字符串
[root@xwq ~]# [ -n "$var" ] && echo 1 || echo 0    #如果字符串长度不为0,则输出1,否则输出0
1
[root@xwq ~]# [ -n $var ] && echo 1 || echo 0   #去掉双引号在这里看起来也对,不过加上会更好
1
[root@xwq ~]# var="xwqcloud"
[root@xwq ~]# [ -z "$var" ] && echo 1 || echo 0    #使用-z,变量长度为0则为真
0
[root@xwq ~]# [ "abc" = "abc" ] && echo 1 || echo 0   #注意"="两端要有空格
1
[root@xwq ~]# [ "abc" = "abb" ] && echo 1 || echo 0
0
[root@xwq ~]# [ "$var" = "xwqcloud" ] && echo 1 || echo 0
1
[root@xwq ~]# [ "$var" == "xwqcloud" ] && echo 1 || echo 0
1
[root@xwq ~]# [ "$var" != "xwqcloud" ] && echo 1 || echo 0
0

例2:

等号两端没有空格带来的问题

[root@xwq ~]# [ "abc"="1" ] && echo 1 || echo 0  #若等号两端不带空格,则会出现明显的逻辑错误
1
[root@xwq ~]# [ "abc" = "1" ] && echo 1 || echo 0   #带空格的就是准确的
0 

结论:字符串比较时若等号两端没有空格,则会导致判断出现逻辑错误,即使语法没有问题,但是结果依然可能不对。

例3:

字符串不加引号可能带来的问题

[root@xwq ~]# var=""  #将变量内容为空
[root@xwq ~]# [ -n "$var" ] && echo 1 || echo 0   #有双引号
0   #返回0,-n不为空为真,因为变量内容为空,因此输出0是对的
[root@xwq ~]# [ -n $var ] && echo 1 || echo 0   #去掉双引号
1   #同样的表达式有没有双引号的结果截然相反,可见双引号的重要性
[root@xwq ~]# [ -z "$var" ] && echo 1 || echo 0  #如果字符串长度为0,则输出1,否则输出0
1
  • 强调字符串比较一定要加双引号

整数二元比较操作符

s-14

例1:

二元数字在[]中使用"<"、">"非标准符合的比较

[root@xwq ~]# [ 2 > 1 ] && echo 1 || echo 0
1
[root@xwq ~]# [ 2 < 1 ] && echo 1 || echo 0
1  #这里逻辑不对,条件不成立,应该返回0,可见,"<"操作符在[]中使用会出现问题
[root@xwq ~]# [ 2 \< 1 ] && echo 1 || echo 0
0   #转义后这里是正确的
[root@xwq ~]# [ 2 = 1 ] && echo 1 || echo 0  #返回结果正确
0
[root@xwq ~]# [ 2 = 2 ] && echo 1 || echo 0   #返回结果正确
1
[root@xwq ~]# [ 2 != 2 ] && echo 1 || echo 0  #返回结果正确
0

例2:

二元数字在[]中使用-gt、-le类符合比较

[root@xwq ~]# [ 2 -gt 1 ] && echo 1 || echo 0
1
[root@xwq ~]# [ 2 -ge 1 ] && echo 1 || echo 0
1
[root@xwq ~]# [ 2 -lt 1 ] && echo 1 || echo 0
0
[root@xwq ~]# [ 2 -le 1 ] && echo 1 || echo 0
0

例3:

二元数字配合不同种类的操作符在[[]]中的比较

[root@xwq ~]# [[ 5 > 6 ]] && echo 1 || echo 0
0
[root@xwq ~]# [[ 5 < 6 ]] && echo 1 || echo 0
1
[root@xwq ~]# [[ 5 != 6 ]] && echo 1 || echo 0
1
[root@xwq ~]# [[ 5 = 6 ]] && echo 1 || echo 0
0
[root@xwq ~]# [[ 5 -gt 6 ]] && echo 1 || echo 0
0
[root@xwq ~]# [[ 5 -lt 6 ]] && echo 1 || echo 0
1

例4:

二元数字在(())中的比较

[root@xwq ~]# (( 3>2 )) && echo 1 || echo 0
1
[root@xwq ~]# (( 3<2 )) && echo 1 || echo 0
0
[root@xwq ~]# (( 3==2 )) && echo 1 || echo 0
0

小结:

1、整数加双引号的比较是对的

2、[[]]中用类似-eq等的写法是对的,[[]]中类似>、<的写法也可能不对,有可能会只比较第一位,逻辑结果不对

3、[]中类似>、<的写法在语法上虽然可能没错,但逻辑结果不对,可以使用=、!=正确比较

4、(())中不能使用类似-eq等的写法,可以使用类似>、<的写法

提示 :系统脚本较为常用的组合是[]加-eq、-gt等组合,这也是推荐的用法

逻辑连接符

s-15

提示:

!中文意思是反:与一个逻辑值相反的逻辑值

-a中文意思是与(and &&):两个逻辑值都是为“真”,返回值才是“真”,反之为“假”

-o中文意思是或(or ||):两个逻辑值只要有一个为“真”,返回值就为“真”

例1:

[root@xwq ~]# [ -f /etc/hosts -a -f /etc/services ] && echo 1 || echo 0
1
[root@xwq ~]# [[ -f /etc/hosts && -f /etc/services ]] && echo 1 || echo 0
1
[root@xwq ~]# [ 5 -eq 6 -o 5 -gt 3 ] && echo 1 || echo 0
1
[root@xwq ~]# ((5==6||5>3)) && echo 1 || echo 0
1

小结:逻辑操作符使用总结

[]中用-a,-o,!

[[]]中用&&,||,!

test用法和[]相同

多个[]之间以及多个[[]]之间,或者任意混合中间逻辑操作符都是&&或||

注意[]、[[]]的两端及比较符号两端必须有空格,但是对于(())就不需要

逻辑操作符实战案例

1、开发shell脚本分别实现以定义变量,脚本传参以及read读入的方式比较2个整数大小。用条件表达式(禁止if)进行判断并以屏幕输出的方式提醒用户比较结果。注意:一共开发2个脚本,在用脚本传参和read读入的方式实现时,需要对变量是否为数字及传参个数是否正确给予提示。

方法一:

s-16

方法二:

s-17

2、要求:

1)当用户输入1时,输出”start installing lamp.“然后执行/server/scripts/lamp.sh,脚本内容输出”lamp is installed“后退出脚本

2)当用户输入2时,输出”start installing lnmp“然后执行/server/scripts/lnmp.sh,脚本输出内容”lamp is installed“后退出脚本

3)当输入3时,退出当前菜单脚本;

4)当输入任何其他字符,给出提示”input error“后退出脚本。

5)要对执行的脚本进行相关条件判读,例如:脚本是否存在,是否可执行等。

解答:

[root@xwq]# mkdir -p /server/scripts/
[root@xwq]# cd /server/scripts/
[root@xwq scripts]# echo "echo lnmp is installed" > lnmp.sh
[root@xwq scripts]# echo "echo lamp is installed" > lamp.sh
[root@xwq scripts]# chmod +x lnmp.sh lamp.sh

脚本内容:

s-17
s-18

if条件语句

if条件语句语法说明

  • 单分支结构

语法:

if [条件]
  then
      指令
fi

if [条件];then
    指令
fi

提示:分号相当于命令换行,上面两种语法等同。

特殊写法:if [ -f "$file1" ];then echo 1;fi 相当于:[ -f "$file1" ]&&echo 1

  • 双分支结构

语法:

if [条件]
   then
      指令集
else
      指令集
fi

特殊写法:if [ -f "$file1" ];then echo 1;else echo 0;fi相当于:[ -f "$file1" ]&&echo 1||echo 0

  • 多分支结构

语法:

if 条件
   then
      指令
elif
   then
      指令
else

举例

1、开发shell脚本判断系统剩余内存的大小,如果低于100M就邮件报警给管理员,并且加入系统定时任务每分钟执行一次检查。(重视解决问题的过程)

第一步:获取内存大小

free -m | grep Mem | awk '{print $NF}'

第二步:配置邮件

echo set from=[your qq email] smtp=smtp.qq.com smtp-auth-user=[your qq number] smtp-auth-password=[your email password].smtp-auth=login > /etc/mail.rc

第三部:定时任务

###3 s
*/3 * * * * /bin/sh /server/scripts/4.sh &>/dev/null

完整脚本:

s-20

2、双多分支if条件句举例

1)用if双分支实现对nginx或mysql服务是否正常判断,使用进程数、端口、url的方式判断,如果进程没起,把进程启动

s-21

思考:

a、监控web服务是否正常,不低于5种思路

b、监控db服务是否正常,不低于5种思路

方法:web和db共同方法

(1)端口

  • 本地:netstat/ss/lsof
  • 远程:telnet/nmap/nc

(2)进程(本地)

(3)wget/curl(http方式,判断根据返回值或者返回内容)

(4)header(http),http方式,根据状态码判断

(5)数据库特有,通过mysql客户端连接判断,根据返回值或者内容。

以web为例:

s-22

以mysql为例:

s-16

扩展-1

此处扩展判断字符串是否为数字的多种方法

法一:sed加正则表达式

命令行传参:

组合语法判断1:

[ -n "echo $num|sed 's/[0-9]//g'" -a -n "echo $2|sed 's/[0-9]//g'" ]&&echo "两个参数都必须为数字" && exit 1

组合语法判断2:

[ -n "echo $num|sed 's/[0-9]//g'" -a -n "echo $2|sed 's/[0-9]//g'" ]&&{
echo "两个参数都必须为数字" 
exit 1
}

单个判断语法:

[ -n "echo $1|sed 's/[0-9]//g'" ]&&echo "第一个参数都必须为数字" && exit 1
[ -n "echo $2|sed 's/[0-9]//g'" ]&&echo "第二个参数都必须为数字" && exit 1

法二:变量的子字符串替换加正则表达式

[root@pan ~]# num=yjscloud123
[root@pan ~]# [ -z "echo "${num//[0-9]/}"" ]&& echo 1||echo 0
0
[root@pan ~]# num=123yjscloud123
[root@pan ~]# [ -z "echo "${num//[0-9]/}"" ]&& echo 1||echo 0
0    #这个结果说明前面的结果不为0,即有非数字字符
[root@pan ~]# num=123
[root@pan ~]# [ -z "echo "${num//[0-9]/}"" ]&& echo 1||echo 0
1     #这个结果说明前面的结果去掉数字后为0,即没有非数字字符

法三:变量的子串替换加正则表达式

思路:如果num长度不为0,并把num中的非数字部分删除,然后看结果是不是等于num本身,如果两者都成立就是数字。

[root@pan ~]# [ -n "$num" -a "$num"="${num//[^0-9]/}" ]&& echo "it is num"
it is num

法四:expr计算判断

expr $1 + 0 >/dev/null 2>&1
[ $? -eq 0 ] && echo int

扩展-2(mysql补充)

完整的检查数据库状态的脚本

方法一:

s-24

方法二:

s-25

方法三:

本方法的实现思路是:模拟web服务器,通过mysql账户连接mysql,然后根据返回命令状态或返回内容确认mysql是否正常(推荐)

s-26

扩展-3(web补充)

s-27

输入参数版:

s-28

nmap版:

s-29

如果写脚本通过nc检查端口并监控memcache服务可以用下面的方法:

s-30

|| 版权声明
作者:废权
链接:https://blog.yjscloud.com/archives/76
声明:如无特别声明本文即为原创文章仅代表个人观点,版权归《废权的博客》所有,欢迎转载,转载请保留原文链接。
THE END
分享
二维码
Shell学习笔记(二):入门知识和实战篇
变量的数值计算常见命令 (())、let、expr、bc、$[],这里只介绍(())和expr (())用法: 如果要执行简单的整数运算,只需将特定的算术表达式用"$(("和……
<<上一篇
下一篇>>
文章目录
关闭
目 录