Linux云计算 |【第二阶段】SHELL-DAY2

主要内容:

条件测试(字符串比较、整数比较、文件状态)、IF选择结构(单分支、双分支、多分支)、For循环结构、While循环结构

一、表达式比较评估

test 命令是 Unix 和 Linux 系统中用于评估条件表达式的命令。它通常用于 shell 脚本中,以根据条件执行不同的操作。test 命令可以检查文件类型、比较字符串和整数,以及执行逻辑操作。

可以为Shell脚本实现智能化判断的结果,为命令的执行提供最直接的识别依据;针对文件或目录的读/写等状态、数值的大小、字符串是否匹配、多条件组合;

  • 格式:test expression
  • 格式:[ expression ]

或者使用方括号 [ ](注意方括号与表达式之间要有空格)

注意:条件测试操作本身不显示出任何信息。测试的条件是否成立主要体现在命令执行后的返回状态(即 ?),所以可以在测试后查看变量?的值来做出判断,或者结合&&、||等逻辑操作显示出结果(或作其他操作)

文件测试

  • -e file:检查文件是否存在。
  • -f file:检查文件是否存在且为普通文件。
  • -d file:检查文件是否存在且为目录。
  • -r file:检查文件是否存在且可读。
  • -w file:检查文件是否存在且可写。
  • -x file:检查文件是否存在且可执行。
  • -s file:检查文件是否存在且大小大于0。

字符串比较

  • str1 = str2:检查字符串是否相等。
  • str1 != str2:检查字符串是否不相等。
  • -z str:检查字符串是否为空。
  • -n str:检查字符串是否非空。

整数比较

  • int1 -eq int2:检查整数是否相等。
  • int1 -ne int2:检查整数是否不相等。
  • int1 -lt int2:检查整数是否小于。
  • int1 -le int2:检查整数是否小于等于。
  • int1 -gt int2:检查整数是否大于。
  • int1 -ge int2:检查整数是否大于等于。

逻辑操作

  • ! expression:逻辑非。
  • expression1 -a expression2:逻辑与(AND)。
  • expression1 -o expression2:逻辑或(OR)。

二、常用表达式

1、字符串比较测试

格式:[ 操作符 字符串 ] //查看变量的值是否为空

  • -z str:检查字符串是否为空
  • -n str:检查字符串是否非空

注意:格式必须要有空格

例如:

bash 复制代码
[root@svr7 ~]# a=100
[root@svr7 ~]# [ -z $a ]     //判断变量a为空
[root@svr7 ~]# echo $?
1
可以简化为如下形式:
[root@svr7 ~]# a=100;[ -z $a ];echo $?    //利用【;】号可隔开表达式
1
 
[root@svr7 ~]# [ ! -z $a ]    //判断变量a不为空
[root@svr7 ~]# echo $?
0
[root@svr7 ~]# [ -n $a ]     //判断变量a不为空
[root@svr7 ~]# echo $?
0

例如:

bash 复制代码
[root@svr5 ~]# var1="nb" ; var2=""
[root@svr5 ~]# [ -z "$var1" ] && echo "空值" || echo "非空值"    //-z查看字符串值为空
非空值
[root@svr5 ~]# [ -z $var2 ] && echo "空值" || echo "非空值"
空值               //变量var2已设置,但无任何值,视为空

常见报错:【! -z】在!与 -z间需要加空格

bash 复制代码
[root@svr7 ~]# [ !-z $a ]
-bash: !-z: event not found

格式:[ 字符串1 操作符 字符串2 ] //查看变量的值是否相同

  • str1 == str2:检查字符串是否相等
  • str1 != str2:检查字符串是否不相等

注意:格式必须要有空格

例如:

bash 复制代码
[root@svr7 ~]# [ abc == abc ]     //字符串的值测试是否相同(常量)
[root@svr7 ~]# echo $?     //判断上条命令是否正确(0正确,非0错误)
0
[root@svr7 ~]# [ "root" == $USER ]     //当前用户是否与root相同(变量)
[root@svr7 ~]# echo $?
0
[root@svr7 ~]# [ "root" != $USER ]    //当前用户是否与root不同
[root@svr7 ~]# echo $?
1

**常见报错:**输入格式错误,未有空格

bash 复制代码
[root@svr7 ~]# [abc == abc]
bash: [abc: 未找到命令...

2、整数值比较测试

格式:[ 整数值1 操作符 整数值2 ]

  • int1 -eq int2:检查整数是否相等
  • int1 -ne int2:检查整数是否不相等
  • int1 -lt int2:检查整数是否小于
  • int1 -le int2:检查整数是否小于等于
  • int1 -gt int2:检查整数是否大于
  • int1 -ge int2:检查整数是否大于等于

例如:

bash 复制代码
[root@svr7 opt]# a=10
[root@svr7 opt]# [ $a -eq 9 ];echo $?    //测试10等于9,报错
1
[root@svr7 opt]# [ $a -eq 10 ];echo $?   //测试10等于10
0
[root@svr7 opt]# [ $a -ne 9 ];echo $?     //测试10不等于9
0
[root@svr7 opt]# [ $a -ge 7 ];echo $?      //测试10大于或等于7
0
[root@svr7 opt]# [ $a -le 7 ];echo $?     //测试10小于或等于7
1
[root@svr7 opt]# [ $a -gt 4 ];echo $?    //测试10大于4
0
[root@svr7 opt]# [ $a -lt 4 ];echo $?    //测试10小于4
1

例如:

bash 复制代码
[root@svr5 ~]# X=20    //定义一个测试变量
[root@svr5 ~]# [ $X -eq 20 ] && echo "相等" || echo "不相等"
相等
[root@svr5 ~]# [ $X -eq 30 ] && echo "相等" || echo "不相等"
不相等

[root@svr5 ~]# [ $X -gt 10 ] && echo "大于" || echo "否"
大于
[root@svr5 ~]# [ $X -gt 20 ] && echo "大于" || echo "否"
否
[root@svr5 ~]# [ $X -gt 30 ] && echo "大于" || echo "否"
否

[root@svr5 ~]# [ $X -ge 10 ] && echo "大于或等于" || echo "否"
大于或等于
[root@svr5 ~]# [ $X -ge 20 ] && echo "大于或等于" || echo "否"
大于或等于
[root@svr5 ~]# [ $X -ge 30 ] && echo "大于或等于" || echo "否"
否

例如:提取当前登录的用户数,比较是否大于等于3

bash 复制代码
[root@svr5 ~]# who | wc -l         //确认已登录的用户数
2
[root@svr5 ~]# N=$(who | wc -l)        //赋值给变量N
[root@svr5 ~]# [ $N -ge 3 ] && echo "超过了" || echo "没超过"
没超过

## 上述赋值给变量N及与3比较的操作,可以简化为如下形式:
[root@svr5 ~]# [ $(who | wc -l) -ge 3 ] && echo "超过了" || echo "没超过"
没超过

**常见报错:**参与比较的必须是整数(可以调用变量),比较非整数值时会出错:

bash 复制代码
[root@svr5 ~]# A=20.4
[root@svr5 ~]# [ $A -gt 10 ]     //不支持小数比较
-bash: [: 20.4: integer expression expected

3、文件比较测试

格式:[ 操作符 文件或目录 ]

  • -e file:检查文件是否存在
  • -f file:检查文件是否存在且为普通文件
  • -d file:检查文件是否存在且为目录
  • -r file:检查文件是否存在且可读
  • -w file:检查文件是否存在且可写
  • -x file:检查文件是否存在且可执行
  • -s file:检查文件是否存在且大小大于0

补充:-e 判断文件不关心类型、-f判断文件必须是普通文件、-d判断文件必须是目录

例如:-e 判断对象是否存在(不管是目录还是文件)

bash 复制代码
[root@svr5 ~]# [ -e "/usr/" ] && echo "存在" || echo "不存在"
存在
[root@svr5 ~]# [ -e "/etc/fstab" ] && echo "存在" || echo "不存在"
存在
[root@svr5 ~]# [ -e "/home/nooby" ] && echo "存在" || echo "不存在"
不存在

例如:-d 判断对象是否为目录(存在且是目录)

bash 复制代码
[root@svr5 ~]# [ -d "/usr/" ] && echo "是目录" || echo "不是目录"
是目录
[root@svr5 ~]# [ -d "/etc/fstab" ] && echo "是目录" || echo "不是目录"
不是目录
[root@svr5 ~]# [ -d "/home/nooby" ] && echo "是目录" || echo "不是目录"
不是目录 

例如:-f 判断对象是否为文件(存在且是文件)

bash 复制代码
[root@svr5 ~]# [ -f "/usr/" ] && echo "是文件" || echo "不是文件"
不是文件
[root@svr5 ~]# [ -f "/etc/fstab" ] && echo "是文件" || echo "不是文件"
是文件
[root@svr5 ~]# [ -f "/home/nooby" ] && echo "是文件" || echo "不是文件"
不是文件

例如:-r 判断对象是否可读

此测试对root用户无效,无论文件是否设置r权限,root都可读;

bash 复制代码
[root@svr5 ~]# cp /etc/hosts /tmp/test.txt          //复制一个文件做测试
[root@svr5 ~]# chmod -r /tmp/test.txt              //去掉所有的r权限
[root@svr5 ~]# [ -r "/tmp/test.txt" ] && echo "可读" || echo "不可读"
可读                                              //root测试结果仍然可读

# 切换为普通用户,再执行相同的测试,结果变为"不可读":
[lisi@svr5 ~]$ [ -r "/tmp/test.txt" ] && echo "可读" || echo "不可读"
不可读

例如:-w 判断对象是否可写

此测试同样对root用户无效,无论文件是否设置w权限,root都可写;

bash 复制代码
[root@svr5 ~]# chmod -w /tmp/test.txt             //去掉所有的w权限
[root@svr5 ~]# ls -l /tmp/test.txt              //确认设置结果
---------- 1 root root 33139 12-11 10:43 /tmp/test.txt
[root@svr5 ~]# [ -w "/tmp/test.txt" ] && echo "可写" || echo "不可写"
可写

# 切换为普通用户,可以正常使用-w测试:
[lisi@svr5 ~]$ ls -l /tmp/test.txt
---------- 1 root root 33139 12-11 10:52 /tmp/test.txt
[lisi@svr5 ~]$ [ -w "/tmp/test.txt" ] && echo "可写" || echo "不可写"
不可写

例如:-x 判断对象是否具有可执行权限

这个取决于文件本身、文件系统级的控制,root或普通用户都适用:

bash 复制代码
[root@svr5 ~]# chmod 644 /tmp/test.txt          //重设权限,无x
[root@svr5 ~]# ls -l /tmp/test.txt              //确认设置结果
-rw-r--r-- 1 root root 33139 12-11 10:52 /tmp/test.txt
[root@svr5 ~]# [ -x "/tmp/test.txt" ] && echo "可执行" || echo "不可执行"
不可执行
[root@svr5 ~]# chmod +x /tmp/test.txt          //添加x权限
[root@svr5 ~]# [ -x "/tmp/test.txt" ] && echo "可执行" || echo "不可执行"
可执行

4、逻辑分隔操作

格式:命令1 操作符 命令2...

格式:[ 条件1 ] 操作符 [ 条件2 ]...

  • A && B //仅当A命令执行成功,才执行B命令
  • A || B //仅当A命令执行失败,才执行B命令
  • A ; B //执行A命令后执行B命令,两者没有逻辑关系

&&,逻辑与 前面条件成立且后条件也成立,则整个测试结果就为真,就会执行之后的指令;

||,逻辑或 前面条件失败才执行之后的指令,且两条件其中某一条件成立,则测试结果就算为真;

补充:

格式:! expression:逻辑非

格式:expression1 -a expression2:逻辑与(AND)

格式:expression1 -o expression2:逻辑或(OR)

例如:

bash 复制代码
[root@svr7 ~]# [ a == a ] && echo ab   //&&条件都成立,指令执行
ab
[root@svr7 ~]# [ a == b ] && echo ab    //&&其中条件不成立,指令不执行
[root@svr7 ~]# [ a == b ] || echo ab   //||只要遇到条件成立,指令执行;
ab

例如:

bash 复制代码
[root@svr7 ~]# touch a b c     //创建文件a b c
[root@svr7 ~]# ls a && ls b && ls c
a
b
c

解释:第一个&&条件都成立(为真)并全部执行;第二个&&以第一个&&作为条件判断,条件都成立(为真)并执行。最终输出:a b c

bash 复制代码
[root@svr7 ~]# ls a || ls b && ls c
a
c

解释:||条件ls a成立(为真)直接执行,忽略ls b;&&以||结果作为条件判断,条件都成立(为真)并执行,最终输出:a c

bash 复制代码
[root@svr7 ~]# ls a && ls b || ls c
a
b

解释:&&条件都成立(为真)并全部执行,||以&&结果作为条件判断,条件成立(为真)已执行,忽略ls c。最终输出:a b

bash 复制代码
[root@svr7 ~]# ls a || ls b || ls c
a

解释;第一个||条件ls a成立(为真)并执行,忽略ls b;第二个||以第一个||作为条件判断,条件成立且已执行ls a,忽略ls b和ls c。最终输出:a

bash 复制代码
[root@svr7 ~]# ls d || ls b && ls c
ls: 无法访问d: 没有那个文件或目录
b
c

解释:||条件ls d不成立,条件ls b成立(为真)并执行,&&以第一个||作为条件判断,条件成立并执行,最终输出:b c

例如:检查变量X的值是否大于10,且小于30:

bash 复制代码
[root@svr5 ~]# X=20      //设置X变量的值为20
[root@svr5 ~]# [ $X -gt 10 ] && [ $X -lt 30 ] && echo "YES"
YES

例如:只要/tmp/、/var/spool/目录中有一个可写,则条件成立:(/tmp临时文件,权限0)

bash 复制代码
[root@svr5 ~]# [ -w "/tmp/" ] || [ -w "/var/spool/" ] && echo "OK"
OK

案例1:判断用户名是否为管理员,若判断输入值非root,则输出报错信息并退出脚本

bash 复制代码
[root@svr7 opt]# vim /opt/test05.sh
#!/bin/bash
[ root != $USER ] && echo "报错:非管理员用户" && exit    //判断用户非root,报错并退出
yum -y install vsftpd     //安装ftp服务
systemctl restart vsftpd
systemctl enable vsftpd
 
[root@svr7 ~]# su - ABC    //登录其它用户测试
[ABC@svr7 ~]$ bash /opt/test05.sh
报错:非管理员用户

案例2:判断用户名是否为空,若输入值为空,则输出报错信息并退出脚本

bash 复制代码
[root@svr7 opt]# vim /opt/test08.sh
#!/bin/bash
read -p "请输入账号:" user    //定义变量user,用户名
[ -z $user ] && echo "报错:输入账号为空" && exit    //判断用户名为空,报错并退出
useradd $user    //创建用户
stty -echo
read -p "请输入密码:" pass    //定义变量pass,密码
stty echo
echo $pass | passwd --stdin $user    //配置密码

案例3:判断用户的UID是否为0(UID:0为root),当用户的ID不等于0就退出

bash 复制代码
[root@svr7 ~]# vim /opt/test04.sh
#!/bin/bash
[ 0 -ne $UID ] && exit      //用户的ID不等于0就退出
yum -y install httpd &> /dev/null    //安装httpd服务
echo "WEB HELLO" > /var/www/html/index.html
systemctl restart httpd
systemctl enable httpd &> /dev/null

案例4:编写脚本,每2分钟检测服务器是否新增软件包,发现新增则给管理员发邮件

bash 复制代码
[root@svr7 opt]# vim mail-test.sh
#!/bin/bash
x=$(rpm -qa | wc -l)    //定义变量:rpm -qa | wc -l的输出结果
[ $x -gt 1307 ] && echo "服务器软件包超出预定值,请排查!" | mail -s test root    //数值比较,1307为新增软件包前的数量值
[root@svr7 opt]# chmod u+x mail-test.sh     //赋予执行权限

--- 编辑周期性计划任务:
[root@svr7 opt]# crontab -e
crontab: installing new crontab
[root@svr7 opt]# crontab -l
*/2 * * * * /opt/mail-test.sh    //每2分钟运行脚本

--- 测试:
[root@svr7 opt]# mail
Heirloom Mail version 12.5 7/5/10.  Type ? for help.
"/var/spool/mail/root": 4 messages 4 new
>N  4 root                  Fri Apr  2 16:28  18/581   "test"
& 4      
Message  4:
From root@svr7.tedu.cn  Fri Apr  2 16:28:02 2021
Return-Path: <root@svr7.tedu.cn>
X-Original-To: root
Delivered-To: root@svr7.tedu.cn
Date: Fri, 02 Apr 2021 16:28:02 +0800
To: root@svr7.tedu.cn
Subject: test
User-Agent: Heirloom mailx 12.5 7/5/10
Content-Type: text/plain; charset=utf-8
From: root@svr7.tedu.cn (root)
Status: R
 
服务器软件包超出预定值,请排查!

三、IF选择结构

在 shell 脚本中,if 语句用于根据条件执行不同的操作。if 语句可以分为单分支、双分支和多分支结构。下面分别介绍这三种结构及其示例。

1、单分支结构

特点:当"条件成立"时,执行命令序列,否则不执行任何操作;

if单分支的执行流程

  • 语法格式:
bash 复制代码
if condition; then
    # commands to execute if condition is true
fi

示例:

bash 复制代码
#!/bin/bash
if [ 0 -eq $UID ] ;then
  echo "您好,您是管理员"
fi
bash 复制代码
#!/bin/bash
if [ -e /path/to/file ]; then
    echo "File exists"
fi

2、双分支结构

特点:当"条件成立"时,执行命令序列1,否则执行命令序列2;

if双分支的执行流程

  • 语法格式:
bash 复制代码
if condition; then
    # commands to execute if condition is true
else
    # commands to execute if condition is false
fi

示例:

bash 复制代码
#!/bin/bash
if [ 0 -eq $UID ] ;then
  echo "您好,您是管理员"
else
  echo "您好,您不是管理员"
fi
bash 复制代码
#!/bin/bash
if [ -e /path/to/file ]; then
    echo "File exists"
else
    echo "File does not exist"
fi

案例:利用双分支编写Ping测试脚本

任务需求:使用ping命令检测目标主机时,人工可直接判断反馈结果,而脚本却不方便。但是当ping测试成功时,执行状态?的值为0;而ping测试失败时,?的值不为0。因此在Shell脚本中可以利用这一点来判断ping目标主机的成败;

补充:

  • [-c] 指定ping包次数;
  • [-i] 定义ping包间隔时间(缩短发送测试包的间隔秒数)
  • [-W] ping测试IP若不成功,直接反馈(等待反馈的超时秒数)

步骤1:

bash 复制代码
[root@svr7 opt]# ping -c 3 -i 0.2 -W 1 192.168.4.7
PING 192.168.4.7 (192.168.4.7) 56(84) bytes of data.
64 bytes from 192.168.4.7: icmp_seq=1 ttl=64 time=0.030 ms
64 bytes from 192.168.4.7: icmp_seq=2 ttl=64 time=0.032 ms
64 bytes from 192.168.4.7: icmp_seq=3 ttl=64 time=0.035 ms
--- 192.168.4.7 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 399ms
rtt min/avg/max/mdev = 0.030/0.032/0.035/0.005 ms
[root@svr7 opt]# echo $?
0
 
[root@svr7 opt]# ping -c 3 -i 0.2 -W 1 192.168.4.78      //不存在IP
PING 192.168.4.78 (192.168.4.78) 56(84) bytes of data.
--- 192.168.4.78 ping statistics ---
3 packets transmitted, 0 received, 100% packet loss, time 419ms
[root@svr7 opt]# echo $?
1

步骤2:检测单台主机的存活状态

bash 复制代码
[root@svr7 opt]# vim test03.sh     //编写脚本
#!/bin/bash
ping -c 3 -i 0.2 -W 1 192.168.4.7 > /dev/null
if [ $? -eq 0 ] ;then
  echo "Ping通了"
else
  echo "Ping没通"
fi    
[root@svr7 opt]# bash test03.sh
Ping通了
 
[root@svr7 opt]# vim test03.sh     //编写脚本
ping -c 3 -i 0.2 -W 1 192.168.4.78 > /dev/null      //不存在的IP
...
[root@svr7 opt]# bash test03.sh
Ping没通

3、多分支结构

特点:相当于if语句嵌套,针对多个条件分别执行不同的操作;

if多分支的执行流程

  • 语法格式:
bash 复制代码
if condition1; then
    # commands to execute if condition1 is true
elif condition2; then
    # commands to execute if condition2 is true
else
    # commands to execute if no condition is true
fi

示例:

bash 复制代码
score=85   ##定义变量

if [ "$score" -ge 90 ]; then
    echo "Grade: A"
elif [ "$score" -ge 80 ]; then
    echo "Grade: B"
elif [ "$score" -ge 70 ]; then
    echo "Grade: C"
else
    echo "Grade: D"
fi

案例:通过if多分支实现分数判断

bash 复制代码
[root@svr7 opt]# vim test04.sh
#!/bin/bash
read -p "本次月考成绩如何?" num
if [ $num -ge 90 ] ;then
  echo "$num分,优秀!"
elif [ $num -ge 80 ] ;then
  echo "$num分,良好!"
elif [ $num -ge 60 ] ;then
  echo "$num分,及格!"
else
  echo "$num分,继续努力"
fi

总结

if 语句在 shell 脚本中用于根据条件执行不同的操作。通过掌握单分支、双分支和多分支结构,可以编写更灵活和功能强大的脚本。结合 test 命令,可以评估各种条件表达式,进一步增强脚本的功能和实用性。

四、循环结构

在 shell 脚本中,for 循环和 while 循环是两种常用的循环结构,用于重复执行一组命令。下面分别介绍这两种循环结构及其示例。

1、For循环

特点:采用遍历式、列表式的执行流程,通过指定变量从值列表中循环赋值,每次复制后执行固定的一组操作(根据变量的不同取值,有次数的重复执行命令序列)

for循环的执行流程

  • 语法格式1:
bash 复制代码
for variable in list; do
    # commands to execute for each element in the list
done

示例:遍历数字范围

bash 复制代码
#!/bin/bash
for i in {1..5}; do
    echo "Number: $i"
done

示例:遍历数组

bash 复制代码
#!/bin/bash
fruits=("apple" "banana" "cherry")

for fruit in "${fruits[@]}"; do
    echo "Fruit: $fruit"
done

示例:遍历文件列表

bash 复制代码
#!/bin/bash
for file in /path/to/directory/*; do
    if [ -f "$file" ]; then
        echo "File: $file"
    fi
done

例如:通过循环批量显示3个haha

bash 复制代码
[root@svr7 opt]# vim test01.sh
#!/bin/bash
for i in a b c
do
  echo haha
  echo $i
done

# 测试:
[root@svr7 opt]# bash test01.sh
haha
a
haha
b
haha
c

例如:通过循环批量显示5个haha

bash 复制代码
[root@svr7 opt]# vim test01.sh
#!/bin/bash
for i in {1..5}
do
  echo haha
  echo $i
done

# 测试:
[root@svr7 opt]# bash test01.sh
haha
1
haha
2
haha
3
haha
4
haha
5

例如:批量检测多个主机的存活状态

bash 复制代码
[root@svr7 opt]# vim test02.sh
#!/bin/bash
for i in {205..210}
do
    ping -c 3 -i 0.2 -w 1 192.168.4.$i &> /dev/null
    if [ $? -eq 0 ];then
       echo "ping 192.168.4.$i,通了"
    else
       echo "ping 192.168.4.$i,没通"
    fi
done

# 测试:
[root@svr7 opt]# bash test02.sh
ping 192.168.4.205,没通
ping 192.168.4.206,没通
ping 192.168.4.207,通了
ping 192.168.4.208,没通
ping 192.168.4.209,没通
ping 192.168.4.210,没通

例如:批量检测多个主机的存活状态(优化)

bash 复制代码
[root@svr7 opt]# vim test02.sh
#!/bin/bash
x=0
y=0
for i in {205..210}
do
    ping -c 3 -i 0.2 -w 1 192.168.4.$i &> /dev/null
    if [ $? -eq 0 ];then
       echo "ping 192.168.4.$i,通了"
    let x++
    else
       echo "ping 192.168.4.$i,没通"
    let y++
    fi
done
echo "$x台通了,$y台不通"

# 测试:
[root@svr7 opt]# bash test02.sh
ping 192.168.4.205,没通
ping 192.168.4.206,没通
ping 192.168.4.207,通了
ping 192.168.4.208,没通
ping 192.168.4.209,没通
ping 192.168.4.210,没通
1台通了,5台不通

案例:创建users.txt,写入无规律的账户名称,使用for循环读取该文件,批量创建账户并设置密码;

bash 复制代码
[root@svr5 ~]# vim addfor.sh
#!/bin/bash
for i in `cat /root/user.txt`
do
   useradd $i
   echo 123456 | passwd --stdin $i
done

附加扩展知识(C语言风格的for循环语法格式)

2、While循环

特点:while循环属于条件式的执行流程,会反复判断指定的测试条件,只要条件成立即执行固定的一组操作,直到条件变化为不成立为终止。所以while循环的条件一般通过变量来进行控制,在循环体内对变量值做相应改变,以便在适当的时候退出,避免陷入死循环,(条件式循环,反复测试条件,只要成立就执行命令序列,不成立终止)

while循环的执行流程

  • 语法格式1:
bash 复制代码
while condition; do
    # commands to execute while condition is true
done
  • 语法格式2: //【:】条件永远成立,死循环
bash 复制代码
while : do
    # commands to execute while condition is true
done

示例:基本用法

bash 复制代码
counter=1

while [ $counter -le 5 ]; do
    echo "Counter: $counter"
    counter=$((counter + 1))
done

示例:读取文件内容

bash 复制代码
while read -r line; do
    echo "Line: $line"
done < /path/to/file

示例:无限循环

bash 复制代码
while true; do
    echo "This is an infinite loop. Press Ctrl+C to exit."
    sleep 1
done

示例:结合 if 语句使用

bash 复制代码
for file in /path/to/directory/*; do
    if [ -f "$file" ]; then
        echo "File: $file"
    elif [ -d "$file" ]; then
        echo "Directory: $file"
    fi
done

例如:

bash 复制代码
[root@svr7 opt]# vim while01.sh
#!/bin/bash
i=1
while [ $i -le 5 ]
do
        echo "$i"
        let i++        //不加自增,则为死循环,需要使用Ctrl+C终止脚本
done
[root@svr7 opt]# bash while01.sh

例如:

bash 复制代码
[root@svr7 opt]# vim while02.sh
#!/bin/bash
while :      //【:】条件永远成立
do
        echo "hello world"
done
[root@svr7 opt]# bash while02.sh       //死循环,需要使用Ctrl+C终止脚本

案例1:使用系统自带变量RANDOM提取随机数(1-100),使用while :制作死循环

bash 复制代码
[root@svr5 ~]# vim guess.sh
#!/bin/bash
num=$[RANDOM%100+1]
i=0
while :
do
   read -p "随机数1-100,你猜:" guess
   let i++                                 //猜一次,计数器加1,统计猜的次数
   if [ $guess -eq $num ];then
        echo "恭喜,猜对了"
        echo "你猜了$i次"
        exit
   elif [ $guess -gt $num ];then
        echo "猜大了"
   else
        echo "猜小了"
   fi
done

[root@svr5 ~]# chmod +x guess.sh
[root@svr5 ~]# ./guess.sh

案例2:检测192.168.4.0/24网段,列出不在线的主机地址

检测目标是一个网段,其网络部分"192.168.4."可以作为固定的前缀;而主机部分包括从1~254连续的地址,所以可结合while循环和自增变量进行控制。

bash 复制代码
[root@svr5 ~]# vim chknet.sh
#!/bin/bash
i=1
while [ $i -le 254 ]
do
    IP="192.168.4.$i"
    ping -c 3 -i 0.2 -W 1 $IP &> /dev/null
    if [ $? -eq 0 ] ; then
        echo "Host $IP is up."
    else
        echo "Host $IP is down."
    fi
    let i++
done

[root@svr5 ~]# chmod +x chknet.sh

#测试:
[root@svr5 ~]# ./chknet.sh
Host 192.168.4.1 is down.
Host 192.168.4.2 is down.
Host 192.168.4.3 is down.
Host 192.168.4.4 is down.
Host 192.168.4.5 is up.
.. ..
Host 192.168.4.250 is down.
Host 192.168.4.251 is down.
Host 192.168.4.252 is down.
Host 192.168.4.253 is down.
Host 192.168.4.254 is down.

补充:sleep 0.2 //如果系统执行任务消耗cpu比较多,可以每次稍微休息0.2秒


常见报错:判断的测试条件左右未加空格;

bash 复制代码
[root@svr7 opt]# [1 -gt 2]
bash: [1: 未找到命令...
[root@svr7 opt]# [1-gt2]
bash: [1-gt2]: 未找到命令...

常见报错:if语句开始,需要配合使用fi作为判断结束符号;

bash 复制代码
[root@svr7 opt]# vim test.sh
#!/bin/bash
if [ a = a ];then
 echo a
[root@svr7 opt]# bash test.sh
test.sh:行4: 语法错误: 未预期的文件结尾

常见报错:无法对空值进行判断

bash 复制代码
[root@svr7 opt]# vim test.sh
#!/bin/bash
if [ $a -eq 2 ];then
 echo a
fi
[root@svr7 opt]# bash test.sh
test.sh: 第 2 行:[: -eq: 期待一元表达式
报错信息:[: -eq: unary operator expected]

附加扩展知识(C语言风格的for循环语法格式:for ((初值;条件;步长控制)))

bash 复制代码
[root@svr7 opt]# vim test.sh
#!/bin/bash
for ((i=1;i<=5;i+=2))
do
  echo $i
done
[root@svr7 opt]# bash test.sh
1
3
5

常见报错:基本语法错误,for ((初值;条件;步长控制))

bash 复制代码
[root@svr7 opt]# vim test.sh
#!/bin/bash
for (i=1;i<=5;i+=2)
do
  echo $i
done
[root@svr7 opt]# bash test.sh
test.sh:行2: 未预期的符号 `(' 附近有语法错误
test.sh:行2: `for (i=1;i<=5;i+=2)'

常见报错:for循环的执行体,需要嵌入到do和done中间

bash 复制代码
[root@svr7 opt]# vim test.sh
#!/bin/bash
for i in 1 2
  echo $i
[root@svr7 opt]# bash test.sh
test.sh:行3: 未预期的符号 `echo' 附近有语法错误
test.sh:行3: `  echo $i'

总结

for 循环和 while 循环是 shell 脚本中非常有用的工具,用于重复执行一组命令。通过掌握这两种循环结构,可以编写更灵活和功能强大的脚本。结合 if 语句,可以进一步增强脚本的功能和实用性。

小结:

本篇章节为**【第二阶段】SHELL-DAY2**的学习笔记,这篇笔记可以初步了解到条件测试(字符串比较、整数比较、文件状态)、IF选择结构(单分支、双分支、多分支)、For循环结构、While循环结构。


Tip:毕竟两个人的智慧大于一个人的智慧,如果你不理解本章节的内容或需要相关笔记、视频,可私信小安,请不要害羞和回避,可以向他人请教,花点时间直到你真正的理解

相关推荐
sinat_384241094 小时前
使用 npm 安装 Electron 作为开发依赖
服务器
朝九晚五ฺ4 小时前
【Linux探索学习】第十四弹——进程优先级:深入理解操作系统中的进程优先级
linux·运维·学习
自由的dream4 小时前
Linux的桌面
linux
xiaozhiwise4 小时前
Makefile 之 自动化变量
linux
Kkooe5 小时前
GitLab|数据迁移
运维·服务器·git
久醉不在酒5 小时前
MySQL数据库运维及集群搭建
运维·数据库·mysql
意疏7 小时前
【Linux 篇】Docker 的容器之海与镜像之岛:于 Linux 系统内探索容器化的奇妙航行
linux·docker
虚拟网络工程师7 小时前
【网络系统管理】Centos7——配置主从mariadb服务器案例(下半部分)
运维·服务器·网络·数据库·mariadb
BLEACH-heiqiyihu7 小时前
RedHat7—Linux中kickstart自动安装脚本制作
linux·运维·服务器