对于脚本的用途,我们也可以用来处理相关的运算的问题,可以大大方便我们的工作。下面我们来看一下shell脚本的数值运算,条件测试以及if判断语句
数值运算
- 四则运算
类型 | 公式 |
---|---|
加法 | num1 + num2 |
减法 | num1 - num2 |
乘法 | num1 * num2 |
除法 | num1 / num2 |
-取余运算
-求模: **num1 % num2**
- 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 ~]#
- $[ ]、$(())算式替换
–表达式:使用 $[ ] 或者 $()
–乘法操作无需要转义,运算符两侧可以无空格
–引用变量时,可以省略$符号
–计算结果替换表达式本身,可结合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
- 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)
- 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脚本获得识别能力,为命令的执行提供最直接的识别依据
- 如:文件或者目录的读、写状态;数值大小、字符串是否匹配、多条件组合等。
- 语法格式
使用“test 表达式”或者[ 表达式 ]都可以,表达式两边至少要留一个空格。
条件测试操作本身不显示出任何信息。测试的条件是否成立主要体现在命令执行后的返回状态
(即 $?),所以可以在测试后查看变量$?的值来做出判断,或者结合&&、||等逻辑操作显示出结果(或作其他操作) 。
[root@room13pc46 ~]# test "a= a"
[root@room13pc46 ~]# echo $? #0 表示正确,1表示错误
0
[root@room13pc46 ~]# [ a == b ]
[root@room13pc46 ~]# echo $?
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)。
- 整数值比较
- 参与比较的必须是整数(可以调用变量),比较非整数值时会出错:
[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
测试:
在虚拟机上执行这脚本,和计划任务…然后多开几个终端连接这个虚拟机.
- 识别文件/目录状态
符号 | 含义 |
---|---|
-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选择结构
- 格式
#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选择分支:==>单分支、多分支、以及语法格式,注意空格。
写的不好,请大家见谅哈。