shell脚本编程实践(三)

1 数组实践

1.1 基础操作

1.1.1 数组基础

基础知识

简介

数组(Array)是有序的元素序列,它是数据结构在shell当中非常常见的一种数据存储方式,它将有限个类型相同的数据放到一个集合中,这个集合就是数组。

为了操作方便,我们为数组定制一个名称变量,数组内的每一个数据都是数组元素,这些数组元素在集合中有顺序的观念,顺序的位置值我们称为下标。
在这里插入图片描述

数组分类

数组样式-从数据结构的本身出发,它主要有多种数组样式

一维数组
    一维数组是最简单的数组,按照顺序将一系列数据排列下来即可,数组本身没有场景含义。
    数据的表现样式:数组[下标]
    适用场景:编程语言中基于数据的查询、聚合等操作
二维数组
    二维数组是业务场景中常见的数组表现样式,即在一维数组的前提下,扩充了数据元素在场景中的含义。
    数据的表现样式:数组[行下标][列下标]
    适用场景:数据库场景中基于数据的查询、聚合等操作
三维数组
    三维数组是大型业务场景中通用的一种数组表现样式,它是在二维数据的前提下,扩充了数据空间的含义。
    数据的表现样式:数组[行下标][列下标][页下标]
    适用场景:数据分析场景中基于数据的查询、聚合等操作

在这里插入图片描述

注意:
    1 bash支持一维数组(不支持多维数组),并且没有限定数组的大小。数组元素的下标由0开始编号。
    2 获取数组中的元素要利用下标,下标可以是整数或算术表达式,其值应大于或等于0
    3 bash的数组支持稀疏格式(索引名称可以不连续)

1.1.2 数组定义

基础知识

数组创建

在Shell中,用括号来表示数组,数组元素用“空格”符号分割开。定义数组的语法格式:
    array_name=(value1 ... valuen)
注意:
    基于元素的格式,主要有单行定义、多行定义、单元素定义、命令定义等多种样式

语法解读

单行定义
    array_name=(value0 value1 value2 value3)

多行定义
    array_name=(
    value0
    value1
    value2
    value3
    )

单元素定义
    array_name[0]=value0
    array_name[1]=value1
    array_name[2]=value2

注意:
    单元素定义的时候,可以不使用连续的下标,而且下标的范围没有限制。

命令定义就是value的值以命令方式来获取
    file_array=($(ls /tmp/))

简单实践

实践1-单行定义

定制数据数组
[root@localhost ~]# num_list=(123,234,345,456,567)
[root@localhost ~]# echo ${num_list[0]}
123,234,345,456,567

数据元素之间使用空格隔开
[root@localhost ~]# num_list=(123 234 345 456 567)
[root@localhost ~]# echo ${num_list[0]}
123
[root@localhost ~]# echo ${num_list[@]}
123 234 345 456 567

实践2-多行定义

定制数组
[root@localhost ~]# class_one=(
> zhangsan
> lisi
> wangwu
> zhaoliu
> )

查看数组元素
[root@localhost ~]# echo ${class_one[0]}
zhangsan
[root@localhost ~]# echo ${class_one[@]}
zhangsan lisi wangwu zhaoliu

实践3-单元素定义

定制数组
[root@localhost ~]# mix_list[0]=nihao
[root@localhost ~]# mix_list[2]=345
[root@localhost ~]# mix_list[4]="1.23,4.56"

查看数组元素
[root@localhost ~]# echo ${mix_list[1]}
[root@localhost ~]# echo ${mix_list[@]}
nihao 345 1.23,4.56

批量多元素定义
[root@localhost ~]# string_list=([0]="value-1" [3]="value-2")
[root@localhost ~]# echo ${string_list[@]}
value-1 value-2
[root@localhost ~]# echo ${!string_list[@]}
0 3

实践4-命令定义

定制数组元素
[root@localhost ~]# file_array=$(ls *.sh)

查看数组元素
[root@localhost ~]# echo ${file_array[0]}
count_head_feet.sh host_network_test.sh memory_info.sh simple_jumpserver.sh simple_login.sh simple_login_string.sh site_healthcheck.sh test_argnum.sh
[root@localhost ~]# echo ${file_array[1]}
[root@localhost ~]# echo ${file_array[2]}
[root@localhost ~]# echo ${file_array[@]}
count_head_feet.sh host_network_test.sh memory_info.sh simple_jumpserver.sh simple_login.sh simple_login_string.sh site_healthcheck.sh test_argnum.sh

注意:
    对于命令的数组创建来说,它只有一个元素

1.1.3 数组取值

基础知识

简介

对于shell的数组数据来说,获取制定的数组元素主要有两种方法,一种是获取内容,一种是获取其他信息。

语法解读

基于索引找内容
    读取数组元素值可以根据元素的下标值来获取,语法格式如下:
        ${
   array_name[index]}
        ${
   array_name[@]:起始位置:获取数量}
注意:
    获取具体的元素内容,指定其下标值,从0开始
    获取所有的元素内容,下标位置写"@"或者"*"
获取数组索引
    在找内容的时候,有时候不知道数组的索引都有哪些,我们可以基于如下方式来获取,数组的所有索引:
        ${
   !array_name[index]}
注意:
    获取所有的元素位置,下标位置写"@"或者"*"
获取数组长度的方法与获取字符串长度的方法相同,格式如下:
    ${
   #array_name[index]}
注意:
    获取具体的元素长度,指定其下标值,从0开始
    获取所有的元素个数,下标位置写"@"或者"*"
从系统中获取所有的数组
    declare -a

简单实践

实践1-基于索引找内容

设定数组内容
[root@localhost ~]# num_list=(123 234 345 456 567)

获取指定位置元素
[root@localhost ~]# echo ${num_list[0]}
123
[root@localhost ~]# echo ${num_list[1]}
234

获取所有位置元素
[root@localhost ~]# echo ${num_list[*]}
123 234 345 456 567
[root@localhost ~]# echo ${num_list[@]}
123 234 345 456 567

获取末尾位置元素
[root@localhost ~]# echo ${num_list[-1]}
567
[root@localhost ~]# echo ${num_list[-2]}
456

获取指定范围元素
[root@localhost ~]# echo ${num_list[@]:1:1}
234
[root@localhost ~]# echo ${num_list[@]:1:3}
234 345 456

实践2-基于内容获取元素

[root@localhost ~]# echo ${!num_list[@]}
0 1 2 3 4
[root@localhost ~]# echo ${!num_list[@]}
0 1 2 3 4

实践3-获取数组长度

获取数组的元素数量
[root@localhost ~]# echo ${#num_list[@]}
5
[root@localhost ~]# echo ${#num_list[*]}
5

获取数据元素的长度
[root@localhost ~]# echo ${#num_list[3]}
3

实践4-获取系统所有数组

设定数组
[root@localhost ~]# num_list=(123 234 345 456 567)

查看所有数组
[root@localhost ~]# declare -a
declare -a BASH_ARGC='()'
declare -a BASH_ARGV='()'
declare -a BASH_LINENO='()'
declare -a BASH_SOURCE='()'
declare -ar BASH_VERSINFO='([0]="4" [1]="2" [2]="46" [3]="2" [4]="release" [5]="x86_64-redhat-linux-gnu")'
declare -a DIRSTACK='()'
declare -a FUNCNAME='()'
declare -a GROUPS='()'
declare -a PIPESTATUS='([0]="0")'
declare -a num_list='([0]="123" [1]="234" [2]="345" [3]="456" [4]="567")'

1.1.4 数组变动

元素修改

简介

数组元素的改其实就是定义数组时候的单元素定义,主要包含两种,元素替换,元素部分内容替换,格式如下
元素内容替换:
    array_name[index]=值
注意:
    在修改元素的时候,index的值一定要保持准确
元素部分内容替换,可以参考字符串替换格式:
    ${
   array_name[index]/原内容/新内容}
注意:
    默认是演示效果,原数组未被修改,如果真要更改需要结合单元素内容替换

简单实践

修改指定位置的值
[root@localhost ~]# num_list[2]=aaa
[root@localhost ~]# echo ${num_list[@]}
123 234 aaa 456 567

替换元素值的特定内容
[root@localhost ~]# echo ${num_list[2]/aa/lualu-}
lualu-a
[root@localhost ~]# num_list[2]=${num_list[2]/aa/lualu-}
[root@localhost ~]# echo ${num_list[@]}
123 234 lualu-a 456 567

元素删除

简介

将shell中的数组删除,可以使用unset来实现,主要有两种情况:删除单元素,删除整个数组。格式如下:
删除单元素
    unset array_name[index]
删除整个数组
    unset array_name

简单实践

删除指定的元素
[root@localhost ~]# echo ${num_list[@]}
123 234 lualu-a 456 567
[root@localhost ~]# unset num_list[2]
[root@localhost ~]# echo ${num_list[@]}
123 234 456 567
[root@localhost ~]# unset num_list[2]
[root@localhost ~]# echo ${num_list[@]}
123 234 456 567
[root@localhost ~]# unset num_list[1]
[root@localhost ~]# echo ${num_list[@]}
123 456 567
[root@localhost ~]# echo ${!num_list[@]}
0 3 4
替换元素值的特定内容
[root@localhost ~]# unset num_list
[root@localhost ~]# echo ${!num_list[@]}

[root@localhost ~]#

1.2 综合实践

1.2.1 数组关联

基础知识

简介

    上一节,我们学习了shell环境下的数组定制的简写方式。数组的定制主要有如下两种:
定制索引数组 - 数组的索引是普通的数字
    declare -a array_name
    - 普通数组可以不事先声明,直接使用

定制关联数组 - 数组的索引是自定义的字母
    declare -A array_name
    - 关联数组必须先声明,再使用

简单实践

实践1-定制索引数组

定制一个空内容的数组
[root@localhost ~]# declare -a course
[root@localhost ~]# declare -a | grep course
declare -a course='()'

定制一个包含元素的数组
[root@localhost ~]# course=(yuwen shuxue yingyu)
[root@localhost ~]# declare -a | grep course
declare -a course='([0]="yuwen" [1]="shuxue" [2]="yingyu")'

实践2-定制关联数组

定制关联数组
[root@localhost ~]# declare -A score
[root@localhost ~]# declare -a | grep score
[root@localhost ~]# declare -A | grep score
declare -A score='()'

关联数组和数字索引数组不能通用
[root@localhost ~]# declare -a score
-bash: declare: score: 无法将关联数组转化为索引数组
关联数组的操作
[root@localhost ~]# declare -A | grep score
declare -A score='([yingyu]="32" [yuwen]="67" [shuxue]="65" )'
[root@localhost ~]# echo ${!score[@]}
yingyu yuwen shuxue
[root@localhost ~]# echo ${score[@]}
32 67 65

1.2.2 数组案例

信息统计

需求

分别打印CPU 1min 5min 15min load负载值
命令提示:
    uptime

信息显示:
    CPU 1 min平均负载为: 0.00
    CPU 5 min平均负载为: 0.01
    CPU 15 min平均负载为: 0.05

编写脚本

查看脚本内容
[root@localhost ~]# cat cpu_load.sh
#!/bin/bash
# 功能:采集系统cpu负载信息
# 版本:v0.1
# 作者:书记
# 联系:www.superopsmsb.com

# 获取CPU负载情况
cpu_load=($(uptime | tr -s " " | cut -d " " -f 11-13 | tr "," " "))

# 信息输出
echo -e "\e[31m\t系统cpu负载信息\e[0m"
echo -e "\e[32m================================"
echo "CPU 1 min平均负载为: ${cpu_load[0]}"
echo "CPU 5 min平均负载为: ${cpu_load[1]}"
echo "CPU 15 min平均负载为: ${cpu_load[2]}"
echo -e "================================\e[0m"
脚本执行后效果
[root@localhost ~]# /bin/bash cpu_load.sh
        系统cpu负载信息
================================
CPU 1 min平均负载为: 0.00
CPU 5 min平均负载为: 0.01
CPU 15 min平均负载为: 0.05
================================

服务管理

需求

服务的管理动作有:
    "启动" "关闭" "重启" "重载" "状态"
服务的管理命令有:
    "start" "stop" "restart" "reload" "status"
选择不同的动作,输出不同的服务执行命令,格式如下:
    systemctl xxx service_name

编写脚本

[root@localhost ~]# cat service_manager.sh
#!/bin/bash
# 功能:定制服务管理的功能
# 版本:v0.1
# 作者:书记
# 联系:www.superopsmsb.com

# 定制普通数组
oper_array=(启动 关闭 重启 重载 状态)
# 定制关联数组
declare -A cmd_array
cmd_array=([启动]=start [关闭]=stop [重启]=restart [重载]=reload [状态]=status)

# 服务的操作提示
echo -e "\e[31m---------------服务的操作动作---------------
 1: 启动  2: 关闭  3: 重启  4: 重载  5: 状态
--------------------------------------------"'\033[0m'

# 选择服务操作类型
read -p "> 请输入服务的操作动作: " oper_num
echo 
echo -e "\e[31m您选择的服务操作动作是:  ${oper_array[$oper_num-1]}\e[0m"
echo -e "\e[32m===============服务的执行动作===============
您即将对服务执行如下命令:
\tsystemctl ${cmd_array[${oper_array[$oper_num-1]}]} service_name
=========================================="'\033[0m'
脚本执行效果
[root@localhost ~]# /bin/bash service_manager.sh
---------------服务的操作动作---------------
 1: 启动  2: 关闭  3: 重启  4: 重载  5: 状态
--------------------------------------------
> 请输入服务的操作动作: 3

您选择的服务操作动作是:  重启
===============服务的执行动作===============
您即将对服务执行如下命令:
        systemctl restart service_name
==========================================

2 流程控制

2.1 基础知识

2.1.1 流程基础

基础知识

编程逻辑

编程语言的目的是通过风格化的编程思路将代码写出来后,实现项目功能的。为了实现功能,我们通过在代码层面通过一些代码逻辑来实现:
    顺序执行 - 程序按从上到下顺序执行
    选择执行 - 程序执行过程中,根据条件选择不同的顺序执行
    循环执行 - 程序执行过程中,根据条件重复执行代码

在这里插入图片描述

shell逻辑

简介

    在shell编程中,默认情况下,处于shell脚本中的命令,它是按照从上到下的方式顺序执行每一条命令,这也导致我们在shell编程的过程中,必须保证每一条命令都能够正常的执行。当然了,真实的生产中的shell编程,不可能仅有这一种编程逻辑。
    许多程序在脚本命令之间需要某种逻辑流控制,这就意味着shell脚本在具体的场景中,根据条件判断选择一条具体的代码逻辑执行特定范围的命令 -- 脚本范围内,允许出现多个场景下的命令块,而控制执行不同命令块的编程逻辑结构,在shell编程中有一个名称 -- 结构化命令。

结构化命令

    结构化命令允许脚本程序根据条件或者相关命令的结果进行判断,执行一些功能命令块,在另外一些条件下,执行跳过这些命令块。
    在shell编程中,这些结构化的命令主要有:
条件逻辑 - 多分支执行命令块
    - if控制语句
    - case控制语句
    - select控制语句
循环逻辑 - 多循环执行命令块
    - for控制语句
    - while控制语句
    - until控制语句
逻辑控制 - 命令块执行过程中,精细化控制
    - continue控制
    - break控制
    - exit控制
    - shift控制

2.2 if条件控制

2.2.1 语法解读

基础知识

简介

条件结构能够根据某个特定的条件,结合内置的测试表达式功能,结合测试的结果状态值对于条件进行判断,然后选择执行合适的任务。在bash中,if命令是条件结构最简单的形式。
    shell中的if语句支持多种条件的决策形式:

在这里插入图片描述

单路决策 - 单分支if语句
    样式:
        if [ 条件 ]
        then
            指令
        fi
    特点:
        单一条件,只有一个输出
双路决策 - 双分支if语句
    样式:
        if [ 条件 ]
        then
            指令1
        else
            指令2
        fi
    特点:
        单一条件,两个输出
多路决策 - 多分支if语句
    样式:
        if [ 条件 ]
        then
            指令1
        elif [ 条件2 ]
        then
            指令2
        else
            指令3
        fi
    特点:
        n个条件,n+1个输出
单行命令写法
    if [ 条件1 ]; then 指令1; elif [ 条件2 ]; then 指令2; ... ; else 指令n; fi
关键点解读:
    1 if 和 then 配套使用
    2 if 和末尾的 fi 顺序反写

内嵌测试语句

    shell的if语句中关于条件判断这块内嵌了如下几种测试表达式语句:
        [ 表达式 ]        - 针对通用的判断场景 
        [[ 表达式 ]]    - 针对扩展的判断场景
        (( 命令 ))     - (())代替let命令来测试数值表达式

简单实践

实践1-单if实践

[root@localhost ~]# cat single_branch_if.sh
#!/bin/bash
# 单分支if语句的使用场景

# 定制普通变量
gender="$1"

# 条件判断逻辑
if [ "${gender}" == "nan" ]
then
   echo "您的性别是 男"
fi
脚本执行效果
[root@localhost ~]# /bin/bash single_branch_if.sh nv
[root@localhost ~]# /bin/bash single_branch_if.sh nan
您的性别是 男

实践2-双if实践

[root@localhost ~]# cat double_branch_if.sh
#!/bin/bash
# 双分支if语句的使用场景

# 定制普通变量
gender="$1"

# 条件判断逻辑
if [ "${gender}" == "nan" ]
then
   echo "您的性别是 男"
else
   echo "您的性别是 女"
fi
脚本执行效果
[root@localhost ~]# /bin/bash double_branch_if.sh
您的性别是 女
[root@localhost ~]# /bin/bash double_branch_if.sh nan
您的性别是 男
  • 7
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值