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

shell基础-数值运算、条件测试、选择分支

2019-04-09 00:16 591 查看

对于脚本的用途,我们也可以用来处理相关的运算的问题,可以大大方便我们的工作。下面我们来看一下shell脚本的数值运算,条件测试以及if判断语句

数值运算

数值运算整数运算小数运算四则运算运算工具
  1. 四则运算
类型 公式
加法 num1 + num2
减法 num1 - num2
乘法 num1 * num2
除法 num1 / num2

-取余运算

-求模: **num1 % num2**

  1. expr 运算工具
    –计算指定的表达式,并输出结果
    –格式:expr 整数1 运算符 整数……
    –乘法操作操作采用 \* 、’*’ 转义, 避免被作为shel通配符
    注意: 符号两边都需要有空格
类型 运算符 示例
加法 + expr 43 + 21、 expr $X + $Y
减法 - expr 43 - 21、 expr $X - $Y
乘法 * expr 43 \* 21、 expr $X \* $Y
除法 / expr 43 / 21、 expr $X / $Y
取余数 % expr 43 % 21、 expr $X % $Y
[root@room13pc46 ~]# x=1234
[root@room13pc46 ~]# expr $x + 78
1312
[root@room13pc46 ~]#  expr $x -78		#注意每个符号之间必须要有空格
expr: 语法错误
[root@room13pc46 ~]#  expr $x - 78
1156
[root@room13pc46 ~]# expr $x \* 78		#避免被作为shel通配符  可以加上 \ 或者  ‘’ 进行转义
96252
[root@room13pc46 ~]# expr $x '*' 78
96252
[root@room13pc46 ~]# expr $x % 78		#注意:取模的结果不会大于除数“78”
64
[root@room13pc46 ~]#
  1. $[ ]、$(())算式替换
    –表达式:使用 $[ ] 或者 $()
    –乘法操作无需要转义,运算符两侧可以无空格
    –引用变量时,可以省略$符号
    –计算结果替换表达式本身,可结合echo输出
[root@svr5 ~]# X=1234
[root@svr5 ~]# echo $[X+78]			#在[ ] 中可以进行过i任意运算,但是不可以运算小数
1312
[root@svr5 ~]# echo $[X*78]
96252
[[root@room13pc46 ~]# a=10;b=10
[root@room13pc46 ~]# expr $a + $b 		#需要在每个变量前面加上$
20
[root@room13pc46 ~]# echo $[a+b]		#在多个变量运算时,需要加 $
20
[root@room13pc46 ~]# echo $[X%78]
64
  1. let工具
    -expr或$[]、$(())方式只进行运算,并不会改变变量的值
    -对变量进行操作,不需要写符号,不显示结果
    -在进行运算时,可以创建变量
    -可以改变变量的值,支持自增、减写法。
[root@room13pc46 ~]# a=10
[root@room13pc46 ~]# expr $a + 2
12
[root@room13pc46 ~]# echo $a
10
[root@room13pc46 ~]# echo $[ a+2]
12
[root@room13pc46 ~]# echo $a
10									#a和b的值没有发生改变
[root@room13pc46 ~]# let a=a+b
[root@room13pc46 ~]# echo $a
20									#可以改变a的值
[root@room13pc46 ~]# let a++		#支持自增操作
[root@room13pc46 ~]# echo $a
21
[root@room13pc46 ~]# expr a++		#expr并不支持自增操作
a++
[root@room13pc46 ~]# echo $a
21
  • 同时let支持一些主流的写法和简写
[root@svr5 ~]# let X++;  echo $X     	    # X++   ==  (X=X+1)
[root@svr5 ~]# let X--;  echo $X        	# X--   == (X=X-1)
[root@svr5 ~]# let X+=78 ; echo $X     	    # X+=78 == (X=X+78)
[root@svr5 ~]# let X-=78 ; echo $X    	 	# X-=78 == (X=X-78)
[root@svr5 ~]# let X*=78 ; echo $X    	 	# X*=78 == (X=X*78)
[root@svr5 ~]# let X/=78 ; echo $X     		# X/=78 == (X=X/78)
[root@svr5 ~]# let X%=78 ; echo $X     		# X%=78 == (X=X%78)
  1. bc 小数运算工具
    —交互运算,可以计算小数之间的运算
    —expr、let、$[ ] ,无法准确运算小数
[root@room13pc46 ~]# bc
bc 1.06.95
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'.
12.34 + 2.54
14.88
23.25+3
26.25
12.0*1.1
13.2
quit			#输入quit就可以退出bc交互环境
[root@room13pc46 ~]#

注意: 1. Linux中每一条任务之间,用 " ;" 来分隔;2。bc 所运算的环境式交互式,在脚本应用当中的bc的使用显然不合理。这是我们可以结合**echo 和 |**的操作,来实现bc的脚本应用

[root@room13pc46 ~]# echo '34+5.678' | bc
39.678
[root@room13pc46 ~]# echo '10/3'|bc
3
[root@room13pc46 ~]# echo 'scale =4;10/3'|bc		#小数位的长度可采用scale=N限制
3.3333
[root@room13pc46 ~]#

条件测试操作

  • 使shell脚本获得识别能力,为命令的执行提供最直接的识别依据
  • 如:文件或者目录的读、写状态;数值大小、字符串是否匹配、多条件组合等。
  1. 语法格式
    使用“test 表达式”或者[ 表达式 ]都可以,表达式两边至少要留一个空格。
    条件测试操作本身不显示出任何信息。测试的条件是否成立主要体现在命令执行后的返回状态
    (即 $?),所以可以在测试后查看变量$?的值来做出判断,或者结合&&、||等逻辑操作显示出结果(或作其他操作) 。
[root@room13pc46 ~]# test "a= a"
[root@room13pc46 ~]# echo $?			#0 表示正确,1表示错误
0
[root@room13pc46 ~]# [ a ==  b ]
[root@room13pc46 ~]# echo $?
1										#表示错误
  1. 字符串测试
  • == 比较两个字符串是否相同
#检查当前用户是否为root
#以root身份执行
[root@room13pc46 ~]# [ $USER == "root" ]
[root@room13pc46 ~]# echo $?
0											#结果正确
[root@room13pc46 ~]# su - lisi

#当切换普通用户后,
[lisi@room13pc46 ~]$  [ $USER == "root" ]
[lisi@room13pc46 ~]$ echo $?
1											#结果错误
[lisi@room13pc46 ~]$
  • != 比较两个字符串是否不相同
#检查当前用户是否为root
#以root身份执行
[root@room13pc46 ~]# [ $USER != "root" ]
[root@room13pc46 ~]# echo $?
1										#结果错误
[root@room13pc46 ~]# su - lisi

#当切换普通用户后,
[lisi@room13pc46 ~]$  [ $USER != "root" ]
[lisi@room13pc46 ~]$ echo $?
0										#结果正确
[lisi@room13pc46 ~]$
  • 一行执行多条命令的情况
# A && B                        //仅当A命令执行成功,才执行B命令
# A || B                        //仅当A命令执行失败,才执行B命令
# A ;  B                        //执行A命令后执行B命令,两者没有逻辑关系
# A && B || C                   //1.当A执行成功,会执行B不会执行C; 2.当A执行失败,B不会执行,C会执行
  • -z 检查变量的值是否未设置(空值)
[lisi@room13pc46 ~]$ var1="nb";var2=""
[lisi@room13pc46 ~]$ [ -z "$var1" ] && echo "空值" || echo "非空值"	#""表示以字符形式呈现
非空值
[lisi@room13pc46 ~]$ [  -z $var1 ] && echo "空值" || echo "非空值"
非空值
[lisi@room13pc46 ~]$ [ -z "$var2" ] && echo "空值" || echo "非空值"
空值
[lisi@room13pc46 ~]$ [ ! -z "$var2" ] && echo "空值" || echo "非空值"	# ! 和 [ 、-z 之间有空格
非空值
[lisi@room13pc46 ~]$ [ ! -z $var1 ] && echo "空值" || echo "非空值"
空值
[lisi@room13pc46 ~]$ [ -n "$var1" ] && echo "空值" || echo "非空值"
空值
> 	还有一个-n可以测试变量是否不为空(相当于! -z)。
  1. 整数值比较
  • 参与比较的必须是整数(可以调用变量),比较非整数值时会出错:
[lisi@room13pc46 ~]$ a=20.4
[lisi@room13pc46 ~]$ [ $a -eq 20 ] 	#不支持小数比较
-bash: [: 20.4: 期待整数表达式
[lisi@room13pc46 ~]$
  • 大小比较
符号 含义
-eq 等于(Equal)
-ne 大于等于(Equal)
-gt 大于等于(Equal)
-lt 小于(Equal)
-le 小于等于()
#例子:
[lisi@room13pc46 ~]$ [ $x -eq 21 ]  && echo "相等" || echo "不等于"
不等于
[lisi@room13pc46 ~]$ [ $x -eq 20 ]  && echo "相等" || echo "不等于"
相等
[lisi@room13pc46 ~]$
  • 例子1:使用位置变量创建添加用户的脚本,如果用户没有输入用户名,则退出脚本
#! /bin/bash
#使用位置变量创建添加用户的脚本,如果用户没有输入用户名,则退出脚本
read -p "请输入用户名" u
[ -z $u ] && exit
useradd $u
echo “用户创建成功”
  • 例子2:每分钟检测系统中登陆帐号的数量,如果大于等于3人登陆,发邮件警告"

解题思路:who: 是查看当前用户登陆数量,然后可以利用 "wc -l " 统计行数即可实现检测当前用户数量.
在利用管道来实现判断操作.
最后在通过计划任务来实现每分钟发邮件.

[root@room13pc46 workplace] vim  long_worring.sh
#!/bin/bash
#每分钟检测系统中登陆帐号的数量,如果大于等于3人登陆,发邮件警告
s=`who | wc -l`
[ s -ge 3 ] && echo "worring 操作3人登陆当前系统!!!" -s worring root

[root@room13pc46 workplace]# crontab  -e		#建立计划任务
* * * * * /root/workplace/long_worring.sh

测试:

在虚拟机上执行这脚本,和计划任务…然后多开几个终端连接这个虚拟机.


  1. 识别文件/目录状态
符号 含义
-e 判断文件是否存在 (不管是目录还是文件)
-d 判断对象是否为目录且存在
-f 判断对象是否为文件且存在
-r 判断对象是否可读
-w 判断对象是否可写
-x 判断对象是否可执行
注意:以上选项(除: x 外)均对root无效. x权限对普通用户和root均有效
[root@room13pc46 workplace]# ls
login.sh        makefile 			#login.sh 是一个可执行文件
[root@room13pc46 workplace]# [ -e login.sh  ] 			#不管是文件还是目录,只要存在就行
[root@room13pc46 workplace]# echo $?
0
[root@room13pc46 workplace]# [ -d login.sh  ] 			#既要存在,又要是目录才行
[root@room13pc46 workplace]# echo $?
1
[root@room13pc46 workplace]# [ -f login.sh  ] 				#要求文件
[root@room13pc46 workplace]# echo $?
0
[root@room13pc46 workplace]#echo "hfsjafkf" > test
[root@room13pc46 workplace]

*对于判断有个特殊的情况

[root@room13pc46 workplace]# echo "hfsjafkf" > test
[root@room13pc46 workplace]# ls -ld test
-rwxr-xr-x 1 root root 9 4月   8 15:38 test
[root@room13pc46 workplace]# chmod 000 test
[root@room13pc46 workplace]# ls
[root@room13pc46 workplace]# ls -ld test
---------- 1 root root 9 4月   8 15:38 test
login.sh                 test
[root@room13pc46 workplace]# [ -r test ]
[root@room13pc46 workplace]# echo $?
0
[root@room13pc46 workplace]# [ -x test ]
[root@room13pc46 workplace]# echo $?
1
[root@room13pc46 workplace]#
  • 例子3 利检测$1 目录是否存在,有则退出,无则创建
#!/bin/bash
#利检测$1 目录是否存在,有则退出,无则创建
[ -d $1 ] && exit
mkdir $1
echo "文件创建成功"

[root@room13pc46 workplace]# ls
abc   login.sh   test
[root@room13pc46 workplace]# bash Create_file.sh abc
[root@room13pc46 workplace]# bash Create_file.sh dcs
文件创建成功
[root@room13pc46 workplace]# ls
abc   login.sh  dsc   test

多个条件/操作的逻辑组合

  • &&,逻辑与
#给定条件必须都成立,整个测试结果才为真。检查变量X的值是否大于10,且小于30:
[root@room13pc46 workplace]# X=20                      //设置X变量的值为20
[root@room13pc46 workplace]# [ $X -gt 10 ] && [ $X -lt 30 ] && echo "YES"
YES
  • || 逻辑或
#只要其中一个条件成立,则整个测试结果为真。
#只要/tmp/、/var/spool/目录中有一个可写,则条件成立:
[root@room13pc46 workplace]# [ -w "/tmp/" ] || [ -w "/var/spool/" ] && echo "OK"
OK

使用if选择结构

  1. 格式
#if单分支的语法组成:
if  条件测试		#注意: if(空格)[(空格) 1 == 2 (空格)]  每个之间都需要有空格
then
命令序列
fi

#if多分支的语法组成:
if  条件测试
then
命令序列1
else
例子命令序列2
fi

#if多分支的语法组成:
if    条件测试1 ;then
命令序列1
elif  条件测试2 ;then
命令序列2
else
命令序列n
fi
  • 例子4 检测/media/cdrom目录,若不存在则创建
[root@room13pc46 workplace]# vim mountdir.sh
#!/bin/bash
dir="/media/cdrom"
if [ ! -d $dir ];then
mkdir -p $dir
fi
[root@svr5 ~]# ./mountdir.sh
有了/media/cdrom文件夹以后,再次执行上述脚本,实际上不做任何有效操作:
  • 例子5 检测并判断指定的主机是否可ping通

分析任务需求
使用ping命令检测目标主机时,人工可直接判断反馈结果,而脚本却不方便。但是当ping测试成功时,执行状态$?的值为0;而ping测试失败时,$?的值不为0。因此在Shell脚本中可以利用这一点来判断ping目标主机的成败。
为了节省ping测试时间,可以只发送3个测试包(-c 3)、缩短发送测试包的间隔秒数(-i 0.2)、等待反馈的超时秒数(-W 1)。比如,检查可ping通的主机:

[root@room13pc46 workplace]# ping -c 3 -i 0.2 -W 1 192.166.4.5
PING 192.166.4.5 (192.166.4.5) 56(84) bytes of data.

--- 192.166.4.5 ping statistics ---
3 packets transmitted, 0 received, 100% packet loss, time 419ms

[root@room13pc46 workplace]# echo $?
1

—脚本编写:

#!/bin/bash
[root@room13pc46 workplace]# vim Ping_test.sh
#检测并判断指定的主机是否可ping通
read -p "情输入你要检测的ip:" I
ping $I -c 3 -i 0.2 -W 1 &> /dev/null
if [ $? -eq 0 ];then			#对上一条命令进行判断
echo "通了"
else
echo "不通"
fi

—测试结果:

[root@room13pc46 workplace]# bash Ping_test.sh
情输入你要检测的ip:127.0.0.1
通了
[root@room13pc46 workplace]# bash Ping_test.sh
情输入你要检测的ip:192.166.45.5
通了
[root@room13pc46 workplace]#
  • 例子6利用random生成随机数,用户进行猜
[root@room13pc46 workplace]# vim guess_number.sh
#!/bin/bash
#利用random生成随机数,用户进行猜
a=$[RANDOM%11]
read -p "请输入你的数字(1~10):" N
[  -z $N  ]&& exit			#若用户没有输入数字,则退出
if [ $a -eq $N  ];then
echo "你猜对了"
elif [ $N  -gt  $a  ];then
echo "你猜大了"
else
echo "你猜小了"
fi
  • 测试:
[root@room13pc46 workplace]# bash guess_number.sh
请输入你的数字(1~10):5
你猜小了
[root@room13pc46 workplace]# bash guess_number.sh
请输入你的数字(1~10):
[root@room13pc46 workplace]#
  • 例子7从键盘读取一个论坛积分,判断论坛用户等级

脚本要求:
大于等于90 神功绝世
大于等于80,小于90 登峰造极
大于等于70,小于80 炉火纯青
大于等于60,小于70 略有小成
小于60 初学乍练

#!/bin/bash
#从键盘上读取一个论坛积分,判断用户的等级
read -p "Please input a Num :" Num
if [ $Num -ge 90 ];then
echo "神功绝世"
elif [ $Num -ge 80 ];then
echo "登峰造极"
elif [ $Num -ge 70 ];then
echo "炉火纯青"
elif [ $Num -ge 60 ];then
echo "略有小成"
else
echo "出来乍练"
fi
总结:
  • 运算:1.整数运算 ==>expr、let、 $[] 、$(()) 等工具 2.小数运算:bc
  • 条件测试:test和 [] 的用法,以及字符串、整数比较,还有文件的判断操作
  • 逻辑判断
    if选择分支:==>单分支、多分支、以及语法格式,注意空格。

写的不好,请大家见谅哈。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: