全国协议5人面授小班,企业级独立开发考核,转业者的IT软件工程师基地 登录/注册 | 如何报名
当前位置: 服务端相关   >  Shell 数组
admin · 更新于 2021-08-06

1. Shell 数组概述

我们学习了变量,知道了变量为存储单个元素的最小单元,本节我们来学习数组来存放多个元素的集合。

1.1 Shell 数组是什么

顾名思义,数组就是一系列数据的集合,这个数据就是我们之前学习的存储单个元素的最小单元变量,也就是说将一些列的元素整合到一个集合内,这个集合的名称就叫数组。当然与其他语言一样,数组具备几个条件,在 Shell 中数组仅支持一维数组,数组元素的下标从 0 开始,数组元素没有最大限制等。

1.2 为什么要用数组

与变量类似,当我们操作批量数据的时候,一个一个变量操作非常不便,此时我们可以使用一个数组集合,对整个数组集合进行遍历或其他操作,最终实现批量的效果,数组使得我们的脚本更具扩展性。

1.3 变量与数组的差异

变量是存储单个数据的单元,其在内存中是随机存储的,数组是存储一系列数据的集合,是事先在内存中开辟连续的一系列空间,之后将数组元素有序的存储在其中。

2. 数组的基本使用

2.1 数组的定义

数组的定义有两种方式,可分为直接定义和单元素定义。

2.1.1 直接定义

数组类似于变量定义,只不过将里面的值用小括号括起来,其中每个元素使用空格分割。Shell 是弱类型的,数组中元素的类型可以不一样,例如其中可以包含数字与字符串。

例如:

ARG1=(1 2 3 "hello Shell")
代码块
  • 1

ARG1 为数组名称,其值前三个为数字,最后一个为字符串。

2.1.2 单元素定义

Shell 中数组下标从 0 开始,利用单个元素来定义数组。

例如:

[root@master scripts]# ARG2[0]=1[root@master scripts]# ARG2[1]=2[root@master scripts]# ARG2[2]=3[root@master scripts]# ARG2[3]="hello Shell" 
代码块
  • 1
  • 2
  • 3
  • 4

2.2 元素获取

2.2.1 获取单个元素

与变量的引用一样,数组可以获取单个位置的元素,利用 ${ARG[num]}

例如:

[root@master scripts]# echo ${ARG1[0]}			//获取AEG1数组中第一个元素1[root@master scripts]# echo ${ARG1[3]}			//获取AEG1数组中第四个元素hello Shell
代码块
  • 1
  • 2
  • 3
  • 4

2.2.2 获取全部元素

  • 获取数组值

获取数组全部元素使用 ${ARG[*]} 或 ${ARG[@]}

例如:

[root@master scripts]# echo ${ARG1[@]}1 2 3 hello Shell[root@master scripts]# echo ${ARG1[*]}1 2 3 hello Shell
代码块
  • 1
  • 2
  • 3
  • 4
  • 获取数组下标

获取数组全部下标使用 ${!ARG[*]} 或 ${!ARG[@]}

例如:

[root@master ~]# echo ${!ARG1[@]}0 1 2 3[root@master ~]# echo ${!ARG1[*]}0 1 2 3
代码块
  • 1
  • 2
  • 3
  • 4

2.2.3 获取数组长度

  • 获取整个数组长度

数组长度及数组中元素的个数,可以利用 ${#ARG[*]} 或 ${#ARG[@]},我们发现其实就是在获取数组全部元素前添加#来获取数组个数。

例如:

[root@master scripts]# echo ${#ARG1[*]}4[root@master scripts]# echo ${#ARG1[@]}4
代码块
  • 1
  • 2
  • 3
  • 4
  • 获取单个元素的长度

对于数组中的某个元我们也可以进行长度的获取,可以利用 ${#ARG1[num]}

例如:

[root@master scripts]# echo ${ARG1[@]} 100 2 3 hello Shell 10[root@master scripts]# echo ${ARG1[3]}		//获取第四个元素内容为:hello Shellhello Shell[root@master scripts]# echo ${#ARG1[3]}		//获取四个元素长度为1111
代码块
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

2.2.4 数组元素的修改

数组可以进行一些列对其元素的操作。

  • 修改

对数组元素的修改,直接对单个元素修改即可,例如:

[root@master scripts]# AEG1[0]=100[root@master scripts]# echo ${ARG1[@]}100 2 3 hello Shell
代码块
  • 1
  • 2
  • 3
  • 增加

对数组元素的增加,和修改一致,直接对单个位置元素增加即可,例如:

[root@master scripts]# ARG1[10]=10[root@master scripts]# echo ${ARG1[@]}100 2 3 hello Shell 10[root@master scripts]# echo ${#ARG1[@]}5
代码块
  • 1
  • 2
  • 3
  • 4
  • 5

Tips:在此我们发现元素之前有 4 个元素,我们将下标 10 的元素赋值为 10,数组是按照从前往后顺序赋值的。

  • 删除

删除数组可以使用 unset,unset ARG1[num] 可以删除对应下标的数组元素,如果不带下标则删除数组的全部元素,例如:

[root@master scripts]# echo ${ARG1[@]} 100 3 hello Shell 10[root@master scripts]# unset ARG1[0]			//删除下标为0的元素[root@master scripts]# echo ${ARG1[@]}3 hello Shell 10[root@master scripts]# unset ARG1     		//删除整个数组元素[root@master scripts]# echo ${ARG1[@]}
代码块
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

2.2.5 数组的切片

和其他语言一样,可以对数组进行切片也称截取操作。可以通过 ${AEG1[@或*]:起始位置:长度} 对原数组进行切片,返回的为字符串,例如:

[root@master scripts]# echo ${ARG1[@]}1 2 3 hello Shell[root@master scripts]# echo ${ARG1[@]:0:2}				//从第1个元素往后2个元素进行切片1 2
代码块
  • 1
  • 2
  • 3
  • 4

2.2.6 数组的替换

可以替换数组中的某一个元素,例如我们将 ARG1 数组中的第 1 个元素替换为 110。

[root@master scripts]# echo ${ARG1[@]}1 2 3 hello Shell[root@master scripts]# echo ${ARG1[@]/1/110}110 2 3 hello Shell
代码块
  • 1
  • 2
  • 3
  • 4

3. Shell 数组分类

我们知道了 Shell 中数组的基本操作,来看一下数组的分类。

3.1 普通数组

普通数组就是我们上面以数字为下标的数组,上述的例子都为普通数组。

3.2 关联数组

关联数组是可以用字符串当作数组下标的一类数组,在使用关联数组前,必须先使用 declare -A 声明它,例如:

[root@master ~]# declare -A ARGFILE							//定义管理数组[root@master ~]# ARGFILE=([name1]=Shell [name2]=linux [name3]=arg)		//关联数组元素赋值[root@master ~]# echo ${ARGFILE[@]}							//查看所有元素arg linux Shell[root@master ~]# echo ${ARGFILE[name1]}					//查看索引为name1的元素值Shell
代码块
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

当然也可以对单个元素进行赋值操作, 我们可以看到关联数组就没有排序了,类似于其他语言中的字典,key 值也是字符串形式。

[root@master ~]# declare -A ARGLIST[root@master ~]# ARGLIST[n1]=1[root@master ~]# ARGLIST[n2]=2[root@master ~]# ARGLIST[n3]="hello Shell" [root@master ~]# echo ${ARGLIST[@]}					//获取关联数组的所有值2 hello Shell 1[root@master ~]# echo ${#ARGLIST[@]}				//获取关联数组的元素个数3[root@master ~]# echo ${!ARGLIST[@]}				//获取关联数组的下标n2 n3 n1
代码块
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

4. 实例

4.1 需求

我们想利用数组统计 linux 服务器的每 5 分钟的网络链接情况,查看处于各个时间段的服务器 TCP 链接的情况。

4.2 思路

可以利用 netstat -ant 命令来查看网络链接情况,但是输出的内容我们只关心最后一列的状态,因此我们可以利用 awk 来打印从第二行开始到最后一列状态,由于 awk 命令在后续我们会详解,在此仅作为工具使用,例如:

[root@master ~]# netstat -ant|awk 'NR>2 {print $NF}'LISTEN
LISTEN
ESTABLISHED
TIME_WAIT
代码块
  • 1
  • 2
  • 3
  • 4
  • 5

打印出来的就是最后一列的状态,我们将其内容作为数组的下标,值为其出现的次数,这样就可以统计 TCP 链接到状态,配合定时任务来定时统计服务器的 tcp 链接状态。

4.3 实现

[root@master Shell_args]# cat tcp_status.sh #!/bin/bash# Description: check tcp status# Auth: kaliarch# Email: kaliarch@163.com# function: net check# Date: 2020-03-14 14:00# Version: 1.0# 日志目录LOG_FILE="/tmp/tcp_status.log"# 定义管理数组declare -A TCP_STATUS# 对数组进行内容赋值# 利用netstat命令来过滤出关系的一列数据for status in $(netstat -ant|awk 'NR>2 {print $NF}')do
	# 对状态相同状态的TCP进行数值累加
	let TCP_STATUS[${status}]++done# 将统计完成的TCP链接状态及数据记录到日志中for i in ${!TCP_STATUS[@]}do 
	echo "$(date +%F" "%H:%m)  服务器的TCP状态为: ${i} 的数量为: ${TCP_STATUS[${i}]}" >> ${LOG_FILE}
done# 测试[root@master ~]# bash tcp_status.sh [root@master ~]# cat /tmp/tcp_status.log 2020-03-14 15:03  服务器的TCP状态为: TIME_WAIT 的数量为: 1382020-03-14 15:03  服务器的TCP状态为: ESTABLISHED 的数量为: 5012020-03-14 15:03  服务器的TCP状态为: LISTEN 的数量为: 59
代码块
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

查看我们单独运行脚本已经成功,可以将这个脚本加入 crontab 中,来定时执行,后期就可以通过日志来查看当时服务器的状态了。

5. 注意事项

  • 需要在实战中理解数组的具体用途,尤其注意关联数组的灵活运用;
  • 需要理解数组的全部元素,元素下标以及元素的切片和替换,具体场景配合使用;
  • 数组一般用来统计批量的内容,例如批量文件的计算等,配合其他命令使用。

6. 小结

数组可谓为我们在 Shell 编程中提供了集合类型数据存储的方案,对于批量数据的操作,数组功不可没。在具体的实践中根据数据特征,明确需求是利用数字作为下标的数组,还是使用关联数组,最后在实践中灵活运用数组的整体长度,切片,替换等操作,配合其他命令实现具体业务需求。


为什么选择汉码未来