目录
一、测试
(一)简单条件测试
(二)逻辑测试
1.符号&&
2.符号||
(三)整数比较
(四)字符串比较
1.相等比较
2.不同比较
3.字符串长度检查
4.双中括号 [[ ]]
5.() {}
二、条件测试语句
(一)if条件语句
1.单分支结构
2.双分支结构
3.多分支结构
(二)case
(三)循环语句
1.for语句
2.while语句
3.until语句
4.双重循环和跳出循环
在Shell脚本中,条件判断主要用于控制程序的执行流程
Shell 脚本有时还要判断用户输入的参数,例如像 mkdir 命令一样,当目录不存在则创建,若已经存在则报错,条件测试语句能够测试特定的表达式是否成立,当条件成立时返回值为 0,否则返回其他数值。
使用 test 或 [ 命令进行条件判断
细分测试语句有:文件测试、逻辑测试、整数值比较、字符串比较。
格式1:test 操作符 目录/文件
格式2:[ 操作符 目录/文件 ] :注意[ ] 两边与操作符和条件之间需要有空格
常见的操作符有:
-d | 测试是否为目录(Directory) |
-e | 测试目录或文件是否存在(Exist) |
-f | 测试是否为文件(File) |
-r | 测试当前用户是否有权限读取(Read) |
-w | 测试当前用户是否有权限写入(Write) |
-x | 测试当前用户是否有权限执行(eXcute) |
-L | 测试是否为软连接文件 |
也可以通过help test 进行查看
使用test加测后,如果条件符合,$?会返回0,如果有错误,会返回非0值
比如检测一个文件是否为目录
测试文件是否存在
也可以直接使用方括号进行测试
比如测试一个文件是否有读取权限
在这里讲解一下,判断是否有读取权限,不是看文件本身,而是看实际结果
比如/etc/shadow文件,它本身是所有人都没有任何权限的,但是,作为root用户,可以无视该权限,直接读取
但是执行权限比较特殊,如果属主,属组,其它用户任何一方有执行权限,那么超级用户就会有执行权限,如果所有人都没有,那么,超级用户也没有
使用逻辑运算符&&(与)、||(或)和括号组合多个条件
格式1:[ 表达式1 ] 操作符 [ 表达式2 ] ...
格式2:命令1 操作符 命令2 ...
操作符 | 作用 |
&& | 逻辑的与,"而且"的意思。 |
|| | 逻辑的或,"或者"的意思。 |
! | 逻辑的否。 |
代表逻辑上的”与“,当前面的命令执行成功才会执行后面的命令,判断/dev/cdrom 设备是否存在,若存在则输出exist
| | 是命令行级别的逻辑运算符,用于连接两个命令,如果第一个命令执行后返回非零退出状态(即失败),则执行第二个命令。如果执行成功(即其退出状态码为0),则第二个命令不会被执行
两个符号一般都是连续使用,比如
#$USER是一个变量,显示当前用户名
[root@localhost data]#[ $USER = root ]&&echo "yes" || echo "no"
yes
#如果当前用户名等于root则执行&&符号后面的命令打印yes
#如果不等于则执行||后面的命令打印no
#因为前两个命令都成功了,所以不会执行||后面的命令
[root@localhost data]#[ $USER! = root ]&&echo "yes" || echo "no"
no
#如果当前用户名不等于root则执行&&符号后面的命令打印yes
#如果等于则执行||后面的命令打印no
#因为第一个命令是错误的,当前用户等于root,!否定之后,就不等于root
#所以第二个命令也不会执行,就会执行||后面的命令
语法为:[ 整数 操作符 整数 ]
操作符 | 作用 |
-eq | 判断是否等于 |
-ne | 判断是否不等于 |
-gt | 判断是否大于 |
-lt | 判断是否小于 |
-le | 判断是否等于或小于 |
-ge | 判断是否大于或等于 |
下面进行一下简单的判断
实际应用可以监控磁盘空间的大小触发警报
我们可以写个脚本试一下
下面来进行测试
现在是4,所以是正常的,现在我们手动将它添加一些文件:dd if=/dev/zero of=/boot/bigfile
然后再去执行这个脚本
也可以指定将信息发送位置
mail -s :表示指定邮箱
test:邮件名称
这是时候出去执行脚本,可以在指定邮箱内看到信息
这个脚本的用法可以写到计划任务中去,每隔一段时间执行一次脚本,监控磁盘情况
语法为:[字符串1 操作符 字符串2]
操作符 | 作用 |
= | 比较字符串内容是否相同。 |
!= | 比较字符串内容是否不同。 |
z | 判断字符串内容是否为空。 |
看字符串是否相同,如果相同就会执行echo yes
判断当前用户是否为root用户,不是的话,就输出not root
因为我不是root用户,所以比较内容是正确的,就会执行echo内容
双中括号是中括号的升级版,它支持通配符和正则表达式,提供了更丰富的功能和更好的错误处理机制
在启用双中括号时,需要注意使用语法,其内容使用 “help [ ”命令进行查看
()与{}都可以将多个命令组合在一起,批量执行。但是执行的方式却不相同
():批量执行命令时,会开启一个子bash环境去执行,执行完毕后自动退出
{}:批量执行命令时,会在当前环境执行,可能会影响当前bash环境的操作
我们来测试一下
可以看到,两个符号虽然作用相同,但是还是有明显的区别的
条件测试语句能够让 Shell 脚本根据实际工作灵活调整工作内容,例如判断系统的状态后执行指定的工作,或创建指定数量的用户,批量修改用户密码,这些都可以让Shell 脚本通过条件测试语句完成。
if条件语句分为单分支结构、双分支结构、多分支结构,复杂度逐级上升,但却可以让Shel 脚本更加的灵活。
首先来说单分支结构,仅用if、then、fi关键词组成,只在条件成立后执行。
其语法为:
1|if [判断条件];then
2|需要执行的命令
3|fi
示例:判断目录是否存在,若不存在则自动创建。
#if表示判断,如果这个变量文件不存在
#then表示接下要执行,那么就会执行mkdir -p $DIR
#fi表示结束
双分支结构是由if、then、else、fi 关键词组成,做条件成立或条件不成立的判断。
其基本语法为
1|if [判断条件];then
2|需要执行的命令
3|else
4|条件不成立时需要执行的命令
5|fi
示例:符合条件执行命令1,不符合则执行命令2
多分支结构相对就比较复杂了,是由if、then、else、elif、fi关键词组成,根据多种条件成立的可能性执行不同的
1|if [判断条件1];then
2|命令序列1
3|elif [判断条件2];then
4|命令序列2
5|elif 判断条件3;then
6|命令序列3
7|else
8|以上条件都为假的命令序列 #托底命令
9|fi
示例:赋予的变量值符合哪一个条件,就执行哪一个条件的命令序列
在Shell脚本中,case语句用于实现多分支选择结构。它根据变量的值匹配一系列模式,并执行与之匹配的第一个模式对应的命令序列。根据不同的变量取值,可以执行不同的命令。
基本语法如下:
1 case $变量名 in
2 模式1) # 判断条件
3 命令1... # 判断为该模式后需要执行的命令
4 ;;
5 模式2)
6 命令2...
7 ;;
8 模式3|模式4) # 可以用'|'分隔多个模式进行联合匹配
9 命令3...
10 ;;
11 *)
12 default_commands... # 匹配所有未明确列出的其他情况(可选)
13 ;;
14 esac # 内容的结尾格式,与if语句中的fi类似
示例:判断输入条件为模式几,就该模式设定的命令序列
该脚本表示随意输入一个字符,如果判断为模式1,则输出“你输入的是一个数字”;如果判断为模式2,则输出“你输入的是一个字母”;如果输入的内容与前两项都不匹配,则判断为模式3,输出“你输入的是一个符号”
在Shell脚本中,有多种类型的循环结构,包括 for、while 和 until 循环。
循环的含义是:将某串码段重复多次利用
for:已知次数的情况下
while、unlie:未知次数的情况下
for条件语句会先读取多个不同的变量值,然后逐一执行同一组命令
其执行过程为:
基本语法为:上下两种都可以
1 for 变量名 in 取值列表 ;do
2 命令序列
3 done
————————————————————————————————————————————
1 for 变量名 in 取值列表
2 do
3 命令序列
4 done
示例1:批量创建用户
首先建立一个文件,在里面添加用户名
现在来写一个脚本
执行该脚本后,会批量创建用户
批量删除用户将useradd改为userdel -r
示例2:判断主机是否在线
将需要查询的主机地址输入文件中
需要知道,如果一个IP地址可以ping通,$?的值就为0,不同为非0
下面就写一个脚本进行测试
该脚本表示,如果调用的变量值能ping通,则输出" host IP地址 is online ";反之则输出" host IP地址 is offline "
如果需要同时测试的ip地址较多,可以将信息重定向,并调到后台运行,不影响当前系统操作
执行之后来查看一下
示例2:算数累加,求1-100的和
for i in {1..100}
do
sum=$[sum+i] #sum的默认值为空,for每次调用变量值时sum就会加上这个数,一直加到100
done
echo $sum
这种语法,偏向C语言类的风格
for ((表达式1;表达式2;表达式3))
do
命令序列
done
#表达式1:定义变量并赋初值
#表达式2:决定是否循环,正确则循环,不正确直接退出
#表达式3:决定循环变量如何改变,决定循环什么时候退出
我们使用这一种方法进行算数累加
sum=0 #赋予sum变量最初值
for ((i=0;i<=100;i++))
#i=0:变量初始值,先决条件
#i<=100:判断条件;i小于等于100,如果不正确,直接退出
#i++:变量自身+1
#这条信息的意思是,每次调取这个变量时,都会迭代生成新的+1数值,一直到100结束
do
sum=$[sum+i] #在每次循环中,将当前数值i加到变量sum上
done
echo $sum
++ | 自身变量+1 |
-- | 自身变量-1 |
+=5 | 自身变量+5 |
-=5 | 自身变量-5 |
*=5 | 自身变量*5 |
/=5 | 自身变量/5 |
%=5 | 自身变量%5 |
执行结果为5050
while 条件语句用于重复测试某个条件,当条件成立时则继续重复执行。
1.语法结构
while 判断条件
do
命令1
done
#语法与if相似
while循环一般用于有条件判断的循环,若判断条件为真,则进入循环,当条件为假就跳出循环
2.死循环
在Shell脚本中,while 死循环是指一个 while 循环结构,其条件始终为真,导致循环体内的命令会无限重复执行,除非外部干预(如通过 Ctrl+C 终止程序或在循环体内使用 break、exit等语句跳出循环)
陷入死循环的条件有三种
1 while 条件始终为真
2 while :
3 while true
示例1
批量添加用户,用户名称以user开头
按数字顺序进行编号一共添加10个用户,即user1、user2、user10
初始密码均设为123123
u=1
#初始值
while [ $u -le 10 ]
#条件为真时,会一直循环执行,当变量u大于10时,会结束循环
do
useradd user$u
echo "123123"|passwd --stdin user$u &>>/dev/null
let u++
#每循环一次,变量u的值就会加1,当循环加到11时,while的判断条件为假
done
执行一下脚本看看结果
示例2:随机生成一个1-1000的整数,判断并提示用户输入的值过高或过低,只有当用户猜中才结束程序。脚本中的$RANDOM 是一个随机变量。while后面的true(:)代表该循环会永久循环执行
price=$[RANDOM%1000+1] #设定随机值为1-1000
time=0 #设定输入次数
while true #表示死循环
do
read -p "请输入商品的价格(1-1000):" num
let time++ #猜测次数,每次猜错,循环一次脚本,该变量值就会+1
if [ $num -eq $price ];then #判断条件,如果两个变量相同,则执行下列命令
echo "恭喜你猜中了,商品价格为${num},您一共猜了${time}次"
exit #跳出循环,退出脚本
elif [ $num -lt $price -a $num -gt 0 -a $num -le 1000];then
#如果猜测的价格变量$num大于商品价格变量$price,且输入的数值大于0,小于等于1000,执行下列命令
#-a:表示且的意思,必须同时满足设定条件才可以执行
echo "太低了"
elif [ $num -gt $price -a $num -le 1000 ];then
#如果猜测的价格变量$num小于商品价格变量$price,且输入的数值小于等于1000,执行下列命令
echo "太高了"
else #输入的不正确则执行下列命令
echo "输入有误,请重新输入:"
fi
done
下面来执行一下脚本吧
until 循环与 while 循环类似,while 循环能实现的脚本 until 同样也可以实现,但区别是while 循环在条件为真是继续执行循环,而 until 则是在条件为假时执行循环
示例:
计算1~50的和值
通过循环累加的方式计算1~50的和值
1 a=0
2 sum=0
3 until [ $a -gt 100] #判断条件。$a大于100则条件为真,会退出循环,若小于100,会陷入循环
4 do
5 sum=$[sum+a] #将当前的a的值累加到sum上
6 let a++ #每循环一次,变量值本身+1
7 done
8 echo $sum
执行脚本,查看结果
break跳出单个循环 break n 数字数字是几代表跳出n层循环
我们再做一个实验
当$i=5时,会跳出第一次循环,echo “------”命令还会执行
将break 设为2时,会直接跳出两层循环,因为脚本只有两次循环,所以会直接结束脚本
continue终止某次循环中的命令,但是不会完全终止命令
exit 直接退出脚本:在介绍while语句已经演示过
实战演练
学完本章后,相信对shell脚本已经有了一个基本的了解,我们来做个实验吧
来写一个99乘法表
echo的用法
选项 | 作用 |
---|---|
\r | 光标移至行首,并且不换行 |
\s | 当前shell的名称,如bash |
\t | 插入Tab键,制表符 |
\n | 输出换行 |
\f | 换行,但光标仍停留在原处 |
\ | 表示插入"\"本身转义 |
\b | 表示退格 不显示前一个字符 |
\c | 抑制更多的输出或不换行 |
# 外层循环变量j从1递增到9
for j in {1..9}
do
# 内层循环变量i从1递增到当前的j值
for i in `seq $j`
do
# 使用echo命令结合-e选项启用转义序列,并用\t插入制表符进行对齐
# \c表示不换行,使得同一行内可以连续输出多个结果
echo -e "${i}x${j}=$[i*j] \t\c"
done
# 当内层循环结束时(即完成一行输出后),执行一次换行
echo
done