Shell中的测试及语句

一、测试

在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 ...

操作符 作用
&& 逻辑的与,"而且"的意思。
|| 逻辑的或,"或者"的意思。
逻辑的否。

1.符号&&

代表逻辑上的”与“,当前面的命令执行成功才会执行后面的命令,判断/dev/cdrom 设备是否存在,若存在则输出exist

2.符号||

| | 是命令行级别的逻辑运算符,用于连接两个命令,如果第一个命令执行后返回非零退出状态(即失败),则执行第二个命令。如果执行成功(即其退出状态码为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 判断字符串内容是否为空。

1.相等比较

看字符串是否相同,如果相同就会执行echo yes

2.不同比较

判断当前用户是否为root用户,不是的话,就输出not root

因为我不是root用户,所以比较内容是正确的,就会执行echo内容

3.字符串长度检查

4.双中括号  [[  ]] 

双中括号是中括号的升级版,它支持通配符和正则表达式,提供了更丰富的功能和更好的错误处理机制

在启用双中括号时,需要注意使用语法,其内容使用 “help [ ”命令进行查看

5.() {}

()与{}都可以将多个命令组合在一起,批量执行。但是执行的方式却不相同

():批量执行命令时,会开启一个子bash环境去执行,执行完毕后自动退出

{}:批量执行命令时,会在当前环境执行,可能会影响当前bash环境的操作

我们来测试一下

可以看到,两个符号虽然作用相同,但是还是有明显的区别的

二、条件测试语句

条件测试语句能够让 Shell 脚本根据实际工作灵活调整工作内容,例如判断系统的状态后执行指定的工作,或创建指定数量的用户,批量修改用户密码,这些都可以让Shell 脚本通过条件测试语句完成。

(一)if条件语句

if条件语句分为单分支结构、双分支结构、多分支结构,复杂度逐级上升,但却可以让Shel 脚本更加的灵活。

1.单分支结构

首先来说单分支结构,仅用if、then、fi关键词组成,只在条件成立后执行。

其语法为:

1|if  [判断条件];then
2|需要执行的命令
3|fi

示例:判断目录是否存在,若不存在则自动创建。

#if表示判断,如果这个变量文件不存在

#then表示接下要执行,那么就会执行mkdir  -p $DIR

#fi表示结束

2.双分支结构

双分支结构是由if、then、else、fi 关键词组成,做条件成立或条件不成立的判断。

其基本语法为

1|if  [判断条件];then
2|需要执行的命令
3|else
4|条件不成立时需要执行的命令
5|fi

示例:符合条件执行命令1,不符合则执行命令2

3.多分支结构

多分支结构相对就比较复杂了,是由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

示例:赋予的变量值符合哪一个条件,就执行哪一个条件的命令序列

(二)case

在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:未知次数的情况下

1.for语句

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

for还有另外一种或用法。可以使用help for进行查看

这种语法,偏向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

2.while语句

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

下面来执行一下脚本吧

3.until语句

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

执行脚本,查看结果

4.双重循环和跳出循环

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

相关推荐

  1. 13.bash shellif-then语句

    2024-01-25 23:56:02       38 阅读
  2. Shell教程_不同Shellif-else条件语句差异

    2024-01-25 23:56:02       19 阅读
  3. 常用命令简单shell语句

    2024-01-25 23:56:02       26 阅读
  4. shell语言expect交互

    2024-01-25 23:56:02       36 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-01-25 23:56:02       19 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-01-25 23:56:02       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-01-25 23:56:02       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-01-25 23:56:02       20 阅读

热门阅读

  1. Vue3 Cli5按需导入ElementPlus

    2024-01-25 23:56:02       47 阅读
  2. vue中如何写过滤器

    2024-01-25 23:56:02       35 阅读
  3. Halcon优化模板匹配速度

    2024-01-25 23:56:02       32 阅读
  4. python使用read_sql与to_sql读写数据库

    2024-01-25 23:56:02       31 阅读
  5. swift 进阶知识点

    2024-01-25 23:56:02       29 阅读
  6. C# 实现 XOR 密码

    2024-01-25 23:56:02       28 阅读
  7. android基础知识补漏

    2024-01-25 23:56:02       31 阅读
  8. Qt 信号槽函数异步与同步处理

    2024-01-25 23:56:02       34 阅读
  9. python super()笔记

    2024-01-25 23:56:02       35 阅读
  10. ElasticSearch分词器介绍

    2024-01-25 23:56:02       37 阅读
  11. qml中QtObject类型的使用

    2024-01-25 23:56:02       33 阅读
  12. 关于C#中的Select与SelectMany方法

    2024-01-25 23:56:02       38 阅读
  13. C# DLL嵌套调用时修改生效

    2024-01-25 23:56:02       33 阅读
  14. 地址解析协议

    2024-01-25 23:56:02       37 阅读
  15. MongoDB聚合:$currentOp

    2024-01-25 23:56:02       35 阅读