06数组实践

50 阅读6分钟

数组实践

基础操作

数组基础

数组(Array)是有序的元素序列,它是数据结构在shell当中非常常见的一种数据存储方式,它将有限个类型相同的数据放到一个集合中,这个集合就是数组。为了操作方便,我们为数组定制一个名称变量,数组内的每一个数据都是数组元素,这些数组元素在集合中有顺序的观念,顺序的位置值我们称为下标

image.png

数组分类

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

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

image.png

注意:

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

数组定义

数组创建

在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-单行定义

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

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

echo ${num_list[@]}
123 234 345 456 567

# 实践2-多行定义

# 定制数组
class_one=(
> zhangsan
> lisi
> wangwu
> zhaoliu
> )

# 查看数组元素
echo ${class_one[0]}
zhangsan

echo ${class_one[@]}
zhangsan lisi wangwu zhaoliu

# 实践3-单元素定义

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

# 查看数组元素
echo ${mix_list[1]}

echo ${mix_list[@]}
nihao 345 1.23,4.56

# 批量多元素定义
string_list=([0]="value-1" [3]="value-2")

echo ${string_list[@]}
value-1 value-2

echo ${!string_list[@]}
0 3

# 实践4-命令定义

# 定制数组元素
unset file_array
# 注意:对于命令的数组创建来说,它只有一个元素(此时实际不是数组)
file_array=$(ls *.sh)

# 查看数组元素
echo ${file_array[0]}
count_head_feet.sh host_network_test.sh memory_info.sh simple_jumpserver.sh simple_login_string.sh site_healthcheck.sh test_argnum.sh

echo ${file_array[1]}

echo ${!file_array[@]}
0

unset file_array
# 这样创建数组,会是多个元素
file_array=($(ls *.sh))

echo ${file_array[0]}
count_head_feet.sh

echo ${file_array[@]}
count_head_feet.sh host_network_test.sh memory_info.sh simple_jumpserver.sh simple_login_string.sh site_healthcheck.sh test_argnum.sh

echo ${!file_array[@]}
0 1 2 3 4 5 6

数组取值

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

语法解读

  1. 基于索引找内容,读取数组元素值可以根据元素的下标值来获取,语法格式如下:

    • ${array_name[index]}
    • ${array_name[@]:起始位置:获取数量}

    注意:获取具体的元素内容,指定其下标值,从0开始;获取所有的元素内容,下标位置写"@"或者"*"

  2. 获取数组索引,在找内容的时候,有时候不知道数组的索引都有哪些,我们可以基于如下方式来获取数组的所有索引,${!array_name[@]}${!array_name[*]}

  3. 获取数组长度的方法与获取字符串长度的方法相同,格式如下:${#array_name[index]}。注意:获取具体的元素长度,指定其下标值,从0开始;获取所有的元素个数,下标位置写"@"或者"*"

  4. 从系统中获取所有的数组,declare -a

简单实践

# 实践1-基于索引找内容

# 设定数组内容
num_list=(123 234 345 456 567)
# 获取指定位置元素
echo ${num_list[0]}
123

echo ${num_list[1]}
234

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

echo ${num_list[@]}
123 234 345 456 567

# 获取末尾位置元素
echo ${num_list[-1]}
567

echo ${num_list[-2]}
456

# 获取指定范围元素
echo ${num_list[@]:1:1}
234

echo ${num_list[@]:1:3}
234 345 456

# 实践2-获取数组索引
echo ${!num_list[@]}
0 1 2 3 4

echo ${!num_list[*]}
0 1 2 3 4

# 实践3-获取数组长度

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

echo ${#num_list[*]}
5

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

# 实践4-获取系统所有数组
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 file_array='([0]="count_head_feet.sh" [1]="host_network_test.sh" [2]="memory_info.sh" [3]="simple_jumpserver.sh" [4]="simple_login_string.sh" [5]="site_healthcheck.sh" [6]="test_argnum.sh")'
declare -a num_list='([0]="123" [1]="234" [2]="345" [3]="456" [4]="567")'

数组变动

元素修改

数组元素的修改其实就是定义数组时候的单元素定义,主要包含两种,元素替换,元素部分内容替换,格式如下

  • 元素内容替换,array_name[index]=值,在修改元素的时候,index的值一定要保持准确
  • 元素部分内容替换,${array_name[index]/原内容/新内容},可以参考字符串替换格式。注意:默认是演示效果,原数组未被修改,如果真要更改需要结合单元素内容替换
# 修改指定位置的值
num_list[2]=aaa

echo ${num_list[@]}
123 234 aaa 456 567

# 替换元素值的特定内容
echo ${num_list[2]/aa/lualu-}
lualu-a

echo ${num_list[@]}
123 234 aaa 456 567

num_list[2]=${num_list[2]/aa/lualu-}

echo ${num_list[@]}
123 234 lualu-a 456 567

元素删除

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

  • 删除单元素,unset array_name[index]
  • 删除整个数组,unset array_name
# 删除指定的元素
echo ${num_list[@]}
123 234 lualu-a 456 567

unset num_list[2]
echo ${num_list[@]}
123 234 456 567

unset num_list[2]
echo ${num_list[@]}
123 234 456 567

# 删除数组中的元素,实际是将该下标位置置空,对其它位置没有影响
echo ${!num_list[@]}
0 1 3 4

unset num_list[1]
echo ${num_list[@]}
123 456 567

echo ${!num_list[@]}
0 3 4

# 删除整个数组
unset num_list
echo ${!num_list[@]}

综合实践

数组关联

上一节,我们学习了shell环境下的数组定制的简写方式。数组的定制主要有如下两种:

  • 定制索引数组 - 数组的索引是普通的数字,declare -a array_name,普通数组可以不事先声明,直接使用
  • 定制关联数组 - 数组的索引是自定义的字母,declare -A array_name,关联数组必须先声明,再使用
# 实践1-定制索引数组

# 定制一个空内容的数组
declare -a course

declare -a | grep course
declare -a course='()'

# 定制一个包含元素的数组
course=(yuwen shuxue yingyu)

declare -a | grep course
declare -a course='([0]="yuwen" [1]="shuxue" [2]="yingyu")'

# 实践2-定制关联数组

# 定制关联数组
declare -A score

declare -a | grep score

declare -A | grep score
declare -A score='()'

# 关联数组和数字索引数组不能通用
declare -a score
-bash: declare: score: cannot convert associative to indexed array

# 关联数组的操作
score[yingyu]="32"
score[yuwen]="67"
score[shuxue]="65"

declare -A | grep score
declare -A score='([yingyu]="32" [yuwen]="67" [shuxue]="65" )'

echo ${!score[@]}
yingyu yuwen shuxue

echo ${score[@]}
32 67 65

数组案例

信息统计

需求

分别打印CPU 1min 5min 15min load负载值;命令提示:uptime 信息显示: CPU 1 min平均负载为: 0.00 CPU 5 min平均负载为: 0.01 CPU 15 min平均负载为: 0.05

cpu_load.sh,创建脚本文件,内容如下

#!/bin/bash
# 功能:采集系统cpu负载信息
# 版本:v0.1
# 作者:example
# 联系:www.example.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"
/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

service_manager.sh,创建脚本文件,内容如下

#!/bin/bash
# 功能:定制服务管理的功能
# 版本:v0.1
# 作者:example
# 联系:www.example.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'
/bin/bash service_manager.sh
---------------服务的操作动作---------------
 1: 启动  2: 关闭  3: 重启  4: 重载  5: 状态
--------------------------------------------
> 请输入服务的操作动作: 1

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