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
您的性别是 男