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

news2024/12/25 1:05:38

主要内容:

条件测试(字符串比较、整数比较、文件状态)、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:检查字符串是否非空

注意:格式必须要有空格 

例如:

[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

 例如:

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

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

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

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

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

注意:格式必须要有空格

例如:

[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

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

[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:检查整数是否大于等于

例如:

[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

例如:

[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

[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 "没超过"
没超过

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

[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 判断对象是否存在(不管是目录还是文件)

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

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

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

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

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

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

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

[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都可写;

[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或普通用户都适用:

[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)

例如:

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

例如:

[root@svr7 ~]# touch a b c     //创建文件a b c
[root@svr7 ~]# ls a && ls b && ls c
a
b
c

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

[root@svr7 ~]# ls a || ls b && ls c
a
c

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

[root@svr7 ~]# ls a && ls b || ls c
a
b

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

[root@svr7 ~]# ls a || ls b || ls c
a

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

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

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

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

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

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

[root@svr5 ~]# [ -w "/tmp/" ] || [ -w "/var/spool/" ] && echo "OK"
OK

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

[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:判断用户名是否为空,若输入值为空,则输出报错信息并退出脚本

[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就退出

[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分钟检测服务器是否新增软件包,发现新增则给管理员发邮件

[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单分支的执行流程

  • 语法格式:
if condition; then
    # commands to execute if condition is true
fi

示例:

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

2、双分支结构

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

if双分支的执行流程

  • 语法格式:
if condition; then
    # commands to execute if condition is true
else
    # commands to execute if condition is false
fi

示例:

#!/bin/bash
if [ 0 -eq $UID ] ;then
  echo "您好,您是管理员"
else
  echo "您好,您不是管理员"
fi
#!/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:

[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:检测单台主机的存活状态

[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多分支的执行流程

  • 语法格式:
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

示例:

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多分支实现分数判断

[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:
for variable in list; do
    # commands to execute for each element in the list
done

示例:遍历数字范围

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

示例:遍历数组

#!/bin/bash
fruits=("apple" "banana" "cherry")

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

示例:遍历文件列表

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

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

[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

[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

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

[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,没通

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

[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循环读取该文件,批量创建账户并设置密码;

[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:
while condition; do
    # commands to execute while condition is true
done
  • 语法格式2:  //【:】条件永远成立,死循环
while : do
    # commands to execute while condition is true
done

示例:基本用法

counter=1

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

示例:读取文件内容

while read -r line; do
    echo "Line: $line"
done < /path/to/file

示例:无限循环

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

示例:结合 if 语句使用

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

例如:

[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

例如:

[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 :制作死循环

[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循环和自增变量进行控制。

[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秒


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

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

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

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

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

[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 ((初值;条件;步长控制)))

[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 ((初值;条件;步长控制))

[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中间

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2077006.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

小乌龟运动控制-1 小乌龟划圆圈

目录 第一章 小乌龟划圆圈 第二章 小乌龟走方形 文章目录 目录前言一、准备工作步骤一&#xff1a;创建ROS工作空间步骤二&#xff1a;创建ROS包和节点步骤三&#xff1a;编写Python代码步骤四&#xff1a;运行ROS节点总结 前言 本教程将教会你如何使用Python编写ROS小海龟节…

【SpringCloud】(一文通)优雅实现远程调用-OpenFeign

目 录 一. RestTemplate存在问题二. OpenFeign介绍三. 快速上手3.1 引入依赖3.2 添加注解3.3 编写 OpenFeign 的客户端3.4 远程调用3.5 测试 四. OpenFeign 参数传递4.1 传递单个参数4.2 传递多个参数4.3 传递对象4.4 传递JSON 五. 最佳实践5.1 Feign 继承方式5.1.1 创建⼀个Mo…

马克思发生器有什么用_马克思发生器工作原理

马克思发生器&#xff08;Marx Generator&#xff09;是一种电气装置&#xff0c;用于产生高压脉冲电压。它由多个电容器组成&#xff0c;这些电容器依次连接在一系列开关之后。首先&#xff0c;每个电容器被并联充电至较低的电压。然后&#xff0c;这些电容器被开关依次串联&a…

C++过生日(我给我自己做的生日礼物)

&#x1f680;欢迎互三&#x1f449;&#xff1a;程序猿方梓燚 &#x1f48e;&#x1f48e; &#x1f680;关注博主&#xff0c;后期持续更新系列文章 &#x1f680;如果有错误感谢请大家批评指出&#xff0c;及时修改 &#x1f680;感谢大家点赞&#x1f44d;收藏⭐评论✍ 引言…

电源自动测试系统:测试柜的组成与功能

为了提高电源测试的效率和安全性&#xff0c;电源自动化测试柜是电源ATE自动测试系统的重要设备&#xff0c;不仅对示波器、万用表等测试仪器起保护作用&#xff0c;更是在测试过程中降低了安全风险&#xff0c;方便了电源产品的自动化测试。 电源自动测试系统机柜 电源自动化测…

C++初学(15补充)

15.1、嵌套循环和二维数组 下面讨论如何使用嵌套for循环来处理二维数组。到目前为止&#xff0c;我们一直学的是一维数组&#xff0c;因为每一个数组都可以看作是一行数据。二维数组更像是一个表格——既有数据行也有数据列。C并没有提供二维数组类型&#xff0c;但是用户可以…

电池的入门

目录 化学电池主要参数电池种类常用电池 物理电池太阳能电池 化学电池 主要参数 1.容量 2.标称电压 3.内阻 4.充电终止电压 5.放点终止电压 电池种类 按能否充电分&#xff1a; 原电池&#xff08;Primary Cell&#xff09;&#xff1a;只能放电不能充电的电池&#xff0c…

FastGPT如何增减用户

背景 开源版本的FastGPT默认只有一个超级用户root&#xff0c;为了更好地管理应用和知识库&#xff0c;可以通过操作MongoDB数据库来增加新的用户和团队。 所需环境 已安装并运行的FastGPT实例MongoDB客户端工具&#xff08;如Mongo Shell或Robo 3T等&#xff09; 操作步骤…

一文带你了解React Hooks

目录 一、useState 二、useRef 三、useEffect 四、自定义Hook 五、Hooks使用规则 Hooks原意是“挂钩”&#xff0c;指将类组件中的部分功能直接可以挂钩到函数组件中&#xff0c;例如state、生命周期方法、副作用等功能。 为什么使用Hooks&#xff1f; 封装代码&#xff…

Harmony鸿蒙应用开发:解决Web组件加载本地资源跨域

鸿蒙开发文档中有一节 加载本地页面 提到了可以通过 $rawfile 方法加载本地 HTML 网页&#xff1a; Index.ets 1Web({ src: $rawfile("local.html"), controller: this.webviewController })但是如果在 local.html 中需要引用一些静态资源&#xff0c;例如图片、JS、…

STM32——TIM定时器的输入捕获功能

一、什么是输出比较与输入捕获&#xff1f; 可以看到&#xff1a; 输出比较OC是用于输出一定频率和占空比的PWM波形&#xff0c;可用于电机驱动进行调速等&#xff1b;而输入捕获IC是用于测量PWM波形的频率以及占空比等参数&#xff1b;和他们的名字相反&#xff0c;一个是比…

Datawhale AI夏令营第四期魔搭- AIGC文生图方向 task01笔记

目录 分任务1&#xff1a;跑通baseline 第一步——搭建代码环境 第二步——报名赛事 第三步——在魔搭社区创建PAI实例 分任务2&#xff1a;相关知识学习以及赛题理解 赛题理解&#xff1a; 文生图基本认识&#xff1a; 1. Diffusion Model(扩散模型) 2. LDMs&#x…

嵌入式Linux学习笔记

1.文件操作命令 2.VI编辑器的部分命令 3.Uboot命令设置环境变量 4. uboot 的顶层 Makefile的重点是“make xxx_defconfig”和“make”这两个命令 &#xff0c;分别如下&#xff1a; 5.在串口SecureCRT中利用uboot启动Linux内核的两种方式 6.Linux内核移植到开发板上也可以反…

常见错误导引 不锈钢螺钉的正确选购和使用分析

紧固件或螺钉是用于固定物体的机械工具。它们用于各种场景&#xff0c;从建造房屋、用具、玩具等。紧固件由多种材料制成&#xff0c;所有这些材料都有特定用途紧固件和用途。一些用于制造螺丝的材料包括不锈钢、铁、铜、铝和塑料。它通常会进行某种表面处理以提高其防锈性和/或…

day-40 合并区间

思路 将二维数组按照第一列升序排列&#xff0c;把intervals[0][0]作为第一个区间的起点&#xff0c;将 intervals[0][1]和intervals[1][0]进行比较&#xff0c;如果intervals[0][1]<intervals[1][0]&#xff0c;则不能合并&#xff0c;否则可以合并&#xff0c;将Math.max(…

绝对不能错过的60个Python日常高频写法总结!

一、 数字 1 求绝对值 绝对值或复数的模 In [1]: abs(-6)Out[1]: 62 进制转化 十进制转换为二进制&#xff1a; In [2]: bin(10)Out[2]: 0b1010十进制转换为八进制&#xff1a; In [3]: oct(9)Out[3]: 0o11十进制转换为十六进制&#xff1a; In [4]: hex(15)Out[4]: 0xf…

[ICS] 物理安全

工业控制系统安全气泡类比 这个理念是&#xff0c;为了防御那些无法更新到最新安全控制措施的旧系统&#xff0c;或者由于设备资源有限而无法处理安全控制措施的系统&#xff0c;帮助可视化这种设备的安全策略可以将它们放置在一个肥皂泡或玻璃泡中。泡中的系统和设备彼此信任…

Spring Cloud Stream与Kafka(一)

Spring Cloud Stream与Kafka&#xff08;一&#xff09; ​ 在实际开发过程中&#xff0c;消息中间件用于解决应用解耦&#xff0c;异步消息&#xff0c;流量削峰等问题&#xff0c;实现高可用、高性能、可伸缩和最终一致性架构。不同的消息中间件实现方式不同&#xff0c;内部…

遥感反演保姆级教程:SPSS筛选因子之后如何采用python建模和反演整个研究区?(以反演生物量为例)

SPSS筛选因子之后如何采用python建模和反演整个研究区?&#xff08;以反演生物量为例&#xff09; 引言 在遥感数据分析中&#xff0c;因子筛选和建模是关键步骤。筛选出与目标变量&#xff08;如生物量&#xff09;显著相关的因子&#xff0c;不仅可以提高模型的预测精度&a…

编程世界的平衡术:日常编码与自我提升的和谐共生

前言 在快速迭代的编程世界中&#xff0c;程序员的角色日益复杂且充满挑战&#xff0c;他们不仅是代码的编织者&#xff0c;更是技术进步的推动者。面对日常编码工作的繁重与个人成长的迫切需求&#xff0c;寻找两者之间的平衡点成为了每位程序员必须深思的问题。以下是我的详细…