当前位置: 首页 > news >正文

Linux中shell的循环控制语句和函数讲解

一、循环控制

1.1 基础知识

continue控制 (跳过当此循环)
    - 满足条件的情况下,临时停止当前的循环,直接进入到下一循环
break控制 (结束这个循环)
    - 满足条件的情况下,提前退出当前的循环
exit控制 
    - 直接退出当前循环的程序
shift控制
    - 依次从循环列表中读取读取内容,并将读取的内容从列表中剔除

1.2 exit简介

注意:
    1 在脚本中遇到exit命令,脚本立即终止;终止退出状态取决于exit命令后面的数字
    2 如果exit后面无数字,终止退出状态取决于exit命令前面命令执行结果

实践1- 设定退出状态值

网段内主机地址的存活性探测
[root@192 ~]# ping -c1 -W1 10.0.0.12 &> /dev/null && echo '10.0.0.12 is up' || (echo '10.0.0.12 is unreachable'; exit 1)
10.0.0.12 is up
[root@192 ~]# ping -c1 -W1 10.0.0.13 &> /dev/null && echo '10.0.0.13 is up' || (echo '10.0.0.13 is unreachable'; exit 6)
10.0.0.13 is unreachable
[root@192 ~]# echo $?
6

服务器网址探测
[root@192 ~]# curl -s -o /dev/null baidu.com &> /dev/null && echo 'baidu.com is up' || (echo 'baidu.com is unreachable'; exit 7)
baidu.com is up
[root@192 ~]# curl -s -o /dev/null baidu.com1 &> /dev/null && echo 'baidu.com1 is up' || (echo 'baidu.com1 is unreachable'; exit 7)
baidu.com1 is unreachable
[root@192 ~]# echo $?
7

实践2-嵌套循环中exit退出程序

查看脚本内容
[root@localhost ~]# vim exit_for.sh
#!/bin/bash
# 功能:exit退出脚本程序# 外层循环遍历1-5
for var1 in {1..5}
do# 内层循环遍历a-dfor var2 in {a..d}do# 判断退出条件,var1是2或者var2是c就退出内层循环if [ $var1 -eq 2 -o "$var2" == "c" ]thenexit 111elseecho "$var1 $var2"fidone
done-- 测试
bash exit_for.sh

1.3 break实践

简介

break主要有两种场景的表现样式:
    单循环场景下,break是终止循环
        - 仅有一层 while 、for、until等
    嵌套循环场景下,break是可以终止内层循环和外层循环。
        - 存在多层while、for、until嵌套等

语法格式

break语法格式:
    for 循环列表
    do
        ...
        break num
    done
    注意:
        单循环下,break就代表退出循环
        多循环下,break的num大于嵌套的层数,就代表退出循环

简单实践

实践1-break终止单层循环

查看脚本内容
[root@localhost ~]# vim break_while.sh
#!/bin/bash
# 功能:break退出单层循环
while true
doread -p "输入你的数字,最好在 1 ~ 5: " aNumcase $aNum in1|2|3|4|5)echo "你的数字是 $aNum!";;*)echo "你选择的数字没在 1 ~ 5, 退出!"break;;esac
done-- 测试
bash break_while.sh

实践2-多层循环下break退出内层循环

[root@localhost ~]# vim break_while.sh
#!/bin/bash
# 功能:break退出内层循环# 外层循环遍历1-5
for var1 in {1..5}
do# 内层循环遍历a-dfor var2 in {a..d}do# 判断退出条件,var1是2或者var2是c就退出内层循环if [ $var1 -eq 2 -o "$var2" == "c" ]thenbreakelseecho "$var1 $var2"fidone
done-- 测试
bash break_while.sh

1.4 continue实践

语法格式

continue语法格式:for 循环列表do...continue numdone注意:单循环下,continue就代表跳出当前循环多循环下,continue的num就代表要继续的循环级别

简单实践

实践1-continue跳出当前单层循环

查看脚本内容
[root@localhost ~]# vim continue_while.sh
#!/bin/bash
# 功能:continue退出单层循环
while true
doread -p "输入你的数字,最好在 1 ~ 5: " aNumcase $aNum in1|2|3|4|5)echo "你的数字是 $aNum!";;*)echo "你选择的数字没在 1 ~ 5, 退出!"continue;;esac
done

实践2-多层循环下continue退出内层循环

[root@localhost ~]# vim continue_while.sh
#!/bin/bash
# 功能:continue退出内层循环# 外层循环遍历1-5
for var1 in {1..5}
do# 内层循环遍历a-dfor var2 in {a..d}do# 判断退出条件,var1是2或者var2是c就退出内层循环if [ $var1 -eq 2 -o "$var2" == "c" ]thencontinueelseecho "$var1 $var2"fidone
done

实践3-多层循环下continue退出外层循环

[root@localhost ~]# vim continue_while.sh
#!/bin/bash
# 功能:continue退出外层循环# 外层循环遍历1-5
for var1 in {1..5}
do# 内层循环遍历a-dfor var2 in {a..d}do# 判断退出条件,var1是2或者var2是c就退出内层循环if [ $var1 -eq 2 -o "$var2" == "c" ]thencontinue 2elseecho "$var1 $var2"fidone
done

1.5 shift实践

简介

    shift是一个特殊的循环控制命令,它的特点主要是依次从输入信息列表中获取相关的参数数据值,然后走循环。

语法解读

shift语法格式:for 循环列表do...shiftdone注意:shift 从用户输入的信息中提取第一个位置的数据内容,每走一个循环,从下一个位置获取输入参数

简单实践

实践1-依次获取所有参数的内容

查看脚本效果
[root@localhost ~]# cat shift_get_args.sh
#!/bin/bash
#功能:shift依次从输入的参数列表中获取内容# 定制一套循环逻辑,直到参数位置内容为空
until [ -z "$1" ] 
doecho "脚本的第1个位置参数内容是: $1, 当前脚本参数数量: $#"# 接收完第一个参数后,直接将起始值移至下一个位置shift
done

实践2-创建指定的系统用户

查看脚本效果
[root@localhost ~]# vim shift_add_user.sh
#!/bin/bash
# 功能:shift批量创建指定的用户# 定制批量创建用户的业务逻辑
if [ $# -ne 0 ]
then# 注意: 这里用的是 -n,后面的$1两侧要有"",如果用until语句的话使用 -z表达式while [ -n "$1" ]do# 创建用户useradd $1echo -e "\e[31m用户 $1 创建成功\e[0m"# 移动输入参数shiftdone
elseecho -e "\e[31mUsage: /bin/bash $0 arg_list\e[0m"
fi

二、函数基础

1.1 基础知识

场景需求

    在shell脚本的编写过程中,我们经常会遇到一些功能代码场景:多条命令组合在一起,实现一个特定的功能场景逻辑、一些命令在脚本内部的多个位置频繁出现。在这些场景的代码量往往不多,但是频繁使用的话,会导致脚本的整体逻辑脉络比较松散和框架散乱。
    所以我们需要一种脚本逻辑,不仅仅能够满足松散代码的功能目的,还能精简重复的代码。
    函数就是来满足这种场景的解决方案 -- 函数,也是所谓的面向对象编程的一种表现样式。

函数的优势:
    1. 代码模块化,调用方便,节省内存
    2. 代码模块化,代码量少,排错简单
    3. 代码模块化,可以改变代码的执行顺序

基本语法

定义函数:样式1:标准格式function 函数名{		函数体				}						样式2:简约格式函数名() {		函数体				}
注意:function 的作用和 () 的作用是一样的,都是定义一个函数。函数的名称是自定义的,而且在脚本范围内必须唯一。函数体内是普通的能够正常执行的命令,命令的执行流程符合顺序逻辑。
调用函数:			函数名					
注意:函数名出现在任何位置,就代表在该位置调用函数内代码块的执行。函数名一般在函数定义后调用,否则的话会发生报错。

简单实践

实践1-标准函数的实践

[root@localhost ~]# vim function_simple_test.sh
#!/bin/bash
# 功能:简单函数的定义和调用# 定制一个函数,提示脚本的使用方式
function Usage {echo -e "\e[31m脚本的使用帮助信息: xxx\e[0m"
}# 定制脚本使用逻辑
if [ $# -eq 1 ]
thenecho "您输入的脚本参数是1个"
elseUsage
fi

实践2-变种函数的实践

[root@localhost ~]# vim function_simple_test2.sh
#!/bin/bash
# 功能:简单函数的定义和调用# 定制一个函数,提示脚本的使用方式
Usage() {echo -e "\e[31m脚本的使用帮助信息: xxx\e[0m"
}# 定制脚本使用逻辑
if [ $# -eq 1 ]
thenecho "您输入的脚本参数是1个"
elseUsage
fi

效果是一样的

实践3-函数的调用顺序和名称唯一 实践

[root@localhost ~]# vim function_simple_test3.sh
#!/bin/bash
# 功能:简单函数的定义和调用# 定制一个函数,提示脚本的使用方式
Usage() {echo -e "\e[31m脚本的使用帮助信息: xxx\e[0m"
}
echo "第一次调用效果: "
Usage# 定制同名的函数,提示脚本的使用方式
Usage() {echo -e "\e[31m脚本的使用帮助信息-------: xxx\e[0m"
}
# 定制脚本使用逻辑
if [ $# -eq 1 ]
then# 调用一个后面才会生成的函数func
elseUsage
fi# 定制一个函数
func() {echo "您输入的脚本参数是1个"
}

1.2 函数退出

基础知识

简介

样式1-默认的退出状态
    默认情况下,函数的退出状态是函数体内的最后一条命令的退出状态,可以通过 $? 来获取
样式2-return定制状态返回值
    在函数体内部,通过return定制状态返回值的内容
    注意:
        return的状态返回值必须尽快使用,否则会被其他return的值覆盖
        return的状态返回值必须在 0-255,否则失效

简单实践

实践1-默认退出状态

[root@localhost ~]# vim function_exit_status1.sh
#!/bin/bash
# 功能:函数默认状态返回值# 定制成功运行的函数
ok_func() {echo -e "\e[31m脚本的使用帮助信息: xxx\e[0m"
}
# 定制一个运行失败的函数
err_func() {666666
}
# 定制脚本使用逻辑
if [ $# -eq 1 ]
thenerr_funcecho "错误函数的执行状态返回值: " $?
elseok_funcecho "成功函数的执行状态返回值: " $?
fi

结果显示:
    对于异常的函数来说,默认的状态返回值有安全隐患

实践2-return定制函数的返回值实践

[root@localhost ~]# vim function_exit_status2.sh
#!/bin/bash
# 功能:return定制函数状态返回值# 定制成功运行的函数
ok_func() {echo -e "\e[31m脚本的使用帮助信息: xxx\e[0m"# 定制超范围的状态返回值return 666
}
# 定制一个运行失败的函数
err_func() {666666# 定制状态返回值return 222
}
# 定制脚本使用逻辑
if [ $# -eq 1 ]
thenerr_funcecho "错误函数的执行状态返回值: " $?
elseok_funcecho "成功函数的执行状态返回值: " $?
fi

结果显示:
    return的状态返回值范围必须满足要求

1.3 进阶实践

传参函数

实践1-传参函数实践

查看脚本内容
[root@localhost ~]# vim function_arg_input.sh
#!/bin/bash
# 功能:传参函数定义和调用# 定制数据运算的函数
add_func() {echo $(( $1 + $2 ))
}
sub_func() {echo $(( $1 - $2 ))
}
mul_func() {echo $(( $1 * $2 ))
}
div_func() {echo $(( $1 / $2 ))
}echo -n "4+3="; add_func 4 3
echo -n "4-3="; sub_func 4 3
echo -n "4*3="; mul_func 4 3
echo -n "4/3="; div_func 4 3

脚本传参

实践1-脚本传参函数实践

查看脚本内容
[root@localhost ~]# vim function_arg_scripts.sh
#!/bin/bash
# 功能:脚本传参函数调用# 定制数据运算的函数
add_func() {echo $(( $1 + $2 ))
}
sub_func() {echo $(( $1 - $2 ))
}
mul_func() {echo $(( $1 * $2 ))
}
div_func() {echo $(( $1 / $2 ))
}[ $# -ne 2  ] && echo "必须传递两个数字参数" && exit
echo -n "$1+$2="; add_func $1 $2
echo -n "$1-$2="; sub_func $1 $2
echo -n "$1*$2="; mul_func $1 $2
echo -n "$1/$2="; div_func $1 $2注意:这种简单的脚本传参函数调用,导致大量的位置参数,容易引起混乱,需要改造

实践2-脚本传参函数进阶实践

查看脚本内容
[root@localhost ~]# vim function_arg_scripts2.sh
#!/bin/bash
# 功能:传参函数定义和调用# 接收脚本传参
arg1=$1
arg2=$2
# 定制数据运算的函数
add_func() {num1=$1num2=$2echo $(( ${num1} + ${num2} ))
}
sub_func() {num1=$1num2=$2echo $(( ${num1} - ${num2} ))
}
mul_func() {num1=$1num2=$2echo $(( ${num1} * ${num2} ))
}
div_func() {num1=$1num2=$2echo $(( ${num1} / ${num2} ))
}[ $# -ne 2  ] && echo "必须传递两个数字参数" && exit
echo -n "${arg1}+${arg2}="; add_func ${arg1} ${arg2}
echo -n "${arg1}-${arg2}="; sub_func ${arg1} ${arg2}
echo -n "${arg1}*${arg2}="; mul_func ${arg1} ${arg2}
echo -n "${arg1}/${arg2}="; div_func ${arg1} ${arg2}

结果一样

1.4 综合案例

查看脚本内容
[root@localhost ~]# vim function_systemctl_load.sh
#!/bin/bash
# 功能:采集系统负载信息
# 版本:v0.3
# 作者:书记
# 联系:www.superopsmsb.com# 定制资源类型
resource_type=(CPU MEM)# 定制cpu信息输出函数
cpu_info() {cpu_attribute=(1 5 15)cpu_load=($(uptime | tr -s " " | cut -d " " -f 9-11 | tr "," " "))echo -e "\e[31m\t系统CPU负载信息\e[0m"echo -e "\e[32m================================"for index in ${!cpu_attribute[@]}doecho "CPU ${cpu_attribute[$index]} min平均负载为: ${cpu_load[$index]}" doneecho -e "================================\e[0m"	
}
# 获取内存相关属性信息
mem_info() {free_attribute=(总量 使用 空闲)free_info=($(free -m | grep Mem | tr -s " " | cut -d " " -f 2-4))echo -e "\e[31m\t系统内存负载信息\e[0m"echo -e "\e[32m================================"for index in ${!free_attribute[@]}doecho "内存 ${free_attribute[$index]} 信息为: ${free_info[$index]} M" doneecho -e "================================\e[0m"
}# 服务的操作提示
echo -e "\e[31m---------------查看资源操作动作---------------1: CPU  2: MEM
-------------------------------------------"'\033[0m'
# 选择服务操作类型
while true
doread -p "> 请输入要查看的资源信息类型: " resource_idechocase ${resource_type[$resource_id-1]} in"CPU")cpu_info;;"MEM")mem_info;;*)echo -e "\e[31m\t请输入有效的信息类型\e[0m";;esac
done

三、函数进阶

3.1 函数变量

变量类型

全局变量:
    默认情况下,脚本中的普通变量就是全局变量,作用范围是shell脚本的所有地方,在函数内部也可以正常使用
    而且函数内可以可以修改脚本级别的全局变量
局部变量:
    我们可以通过local语法,将变量的作用范围限制在一段代码块范围中。
    注意:脚本内无法使用local语法,仅限于函数体内

简单实践

实践1-全局变量实践

查看脚本内容
[root@localhost ~]# cat function_env_test.sh
#!/bin/bash
# 功能:全局变量实践# 定制普通的全局变量
message="helloworld"# 定制一个函数,提示脚本的使用方式
function Usage {echo "直接调用脚本的message: ${message}"message="function-message"echo "函数体重置后的message: ${message}"
}# 定制脚本使用逻辑
while true
doread -p "查看变量的方式[ 1-脚本内 | 2-函数内 ]:" typeif [ ${type} == "1" ];then# 直接在脚本环境使用全局变量echo ${message}elif [ ${type} == "2" ];then# 函数内部使用全局变量Usagefi
done

实践2-本地变量实践

查看脚本内容
[root@localhost ~]# vim function_env_test2.sh
#!/bin/bash
# 功能:local定制函数级别的局部变量实践# 定制普通变量
message="helloworld"
local local_env="local"# 定制一个函数,提示脚本的使用方式
function Usage {echo "直接调用脚本的变量: ${message}-${local_env}"local message="function-message"echo "函数体重置后的变量: ${message}-${local_env}"
}# 定制脚本使用逻辑
while true
doread -p "查看变量的方式[ 1-脚本内 | 2-函数内 ]:" typeif [ ${type} == "1" ];then# 直接在脚本环境使用普通变量echo ${message}elif [ ${type} == "2" ];then# 函数内部使用普通变量Usagefi
done

结果一样

3.2 数组传递

基础知识

简介

限制1:
    以变量的方式传递数组给函数,函数内部无法正常使用
限制2:
    我们只能先解析所有数组元素,然后再传递给函数,接着在函数体内部重新组合
限制3:
    函数内部以echo方式输出数组所有元素,然后再函数外部重新组合为数组

简单实践

实践1-函数无法正常接收数据元素

查看脚本内容
[root@localhost ~]# vim function_array_input.sh
#!/bin/bash
# 功能: 函数接收数组元素# 定制功能函数
func_array(){echo "函数内接收的参数: $@"
}# 定制数组变量
myarray=(aa bb cc dd ee)
echo "myarray数组的所有元素有: ${myarray[@]}"# 数组传递给函数
func_array $myarray
脚本执行效果
[root@localhost ~]# /bin/bash function_array_input.sh
myarray数组的所有元素有: aa bb cc dd ee
函数内接收的参数: aa结果显示:虽然我们传递数组给函数,但是函数无法正常接收数组

实践2-函数接收数组

查看脚本内容
[root@localhost ~]# cat function_array_input2.sh
#!/bin/bash
# 功能: 函数接收数组元素# 定制功能函数
func_array(){echo "函数内接收的参数: $@"func_arr=($(echo $@))echo "函数内func_arr的数组元素有: ${func_arr[@]}"
}# 定制数组变量
myarray=(aa bb cc dd ee)
echo "myarray数组的所有元素有: ${myarray[@]}"# 数组解析后,将所有元素传递给函数
func_array ${myarray[@]}
脚本执行效果
[root@localhost ~]# /bin/bash function_array_input2.sh
myarray数组的所有元素有: aa bb cc dd ee
函数内接收的参数: aa bb cc dd ee
函数内func_arr的数组元素有: aa bb cc dd ee

实践3-脚本接收函数内数组

查看脚本内容
[root@localhost ~]# cat function_array_output.sh
#!/bin/bash
# 功能: 脚本接收函数内数组元素# 定制功能函数
func_array(){# 函数体内构造新数组func_arr=($(echo $@))# 生成新数组for (( i=0; i<${#func_arr[@]}; i++ ))donewarray[$i]=$[ ${func_arr[$i]} * 3 ]done# 逐个返回数组元素echo ${newarray[@]}
}# 定制数组变量
myarray=(1 2 3 4 5)
echo "myarray数组的所有元素有: ${myarray[@]}"# 接收函数体返回的数组内容
result=($(func_array ${myarray[@]}))
echo "函数返回的result数组元素:${result[@]}"
脚本执行效果
[root@localhost ~]# /bin/bash function_array_output.sh
myarray数组的所有元素有: 1 2 3 4 5
函数返回的result数组元素:3 6 9 12 15

相关文章:

  • 深度学习小项目合集-视频介绍下自取
  • Ansible小试牛刀
  • Spring Boot循环依赖全场景解析与终极解决方案
  • Cloudreve 私有云盘系统部署
  • 【WSL2】Windows11开启WSL2
  • 2025年渗透测试面试题总结-云南云钺信息安全(云南)有限公司[社招]技术工程师(题目+回答)
  • 麒麟系统集成开发环境Kylin-IDE初体验,菜鸟小白入门教程
  • ceph集群调整pg数量实战(上)
  • MyBatis的#和$符号详解(Java面试)
  • AtCoder Beginner Contest 408
  • 循环冗余码校验CRC码 算法步骤+详细实例计算
  • 【C】十六进制(Hex)与ASCII
  • okhttp 实现长连接的完整方案
  • 降低显存,优化性能方案 MHA MQA GQA MLA MFA
  • 《高等数学》(同济大学·第7版)第四章第一节不定积分的概念与性质
  • CMake测试find_package()命令的相关原理
  • 商品中心—2.商品生命周期和状态的技术文档
  • [FX5U-PLC] 变频器的多段速变频调速控制系统
  • 可视化如何全方位赋能销售工作
  • Windows 文件路径与文件名限制
  • 兼职做一篇微信的网站/网站关键词优化代理
  • 分销系统网站建设/运营是做什么的
  • hao123网址之家设为主页/咖啡seo是什么意思
  • 外贸网站建设哪家公司好/360指数查询工具
  • 微网站设计与开发是什么/分享推广
  • d0906网站建设与管理/宣传推广方案怎么写