Shell 數組
1. Shell 數組概述
我們學習了變量,知道了變量為存儲單個元素的最小單元,本節我們來學習數組來存放多個元素的集合。
1.1 Shell 數組是什么
顧名思義,數組就是一系列數據的集合,這個數據就是我們之前學習的存儲單個元素的最小單元變量,也就是說將一些列的元素整合到一個集合內,這個集合的名稱就叫數組。當然與其他語言一樣,數組具備幾個條件,在 Shell 中數組僅支持一維數組,數組元素的下標從 0 開始,數組元素沒有最大限制等。
1.2 為什么要用數組
與變量類似,當我們操作批量數據的時候,一個一個變量操作非常不便,此時我們可以使用一個數組集合,對整個數組集合進行遍歷或其他操作,最終實現批量的效果,數組使得我們的腳本更具擴展性。
1.3 變量與數組的差異
變量是存儲單個數據的單元,其在內存中是隨機存儲的,數組是存儲一系列數據的集合,是事先在內存中開辟連續的一系列空間,之后將數組元素有序的存儲在其中。
2. 數組的基本使用
2.1 數組的定義
數組的定義有兩種方式,可分為直接定義和單元素定義。
2.1.1 直接定義
數組類似于變量定義,只不過將里面的值用小括號括起來,其中每個元素使用空格分割。Shell 是弱類型的,數組中元素的類型可以不一樣,例如其中可以包含數字與字符串。
例如:
ARG1=(1 2 3 "hello Shell")
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"
2.2 元素獲取
2.2.1 獲取單個元素
與變量的引用一樣,數組可以獲取單個位置的元素,利用 ${ARG[num]}
。
例如:
[root@master scripts]# echo ${ARG1[0]} //獲取AEG1數組中第一個元素
1
[root@master scripts]# echo ${ARG1[3]} //獲取AEG1數組中第四個元素
hello Shell
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
- 獲取數組下標
獲取數組全部下標使用 ${!ARG[*]}
或 ${!ARG[@]}
。
例如:
[root@master ~]# echo ${!ARG1[@]}
0 1 2 3
[root@master ~]# echo ${!ARG1[*]}
0 1 2 3
2.2.3 獲取數組長度
- 獲取整個數組長度
數組長度及數組中元素的個數,可以利用 ${#ARG[*]}
或 ${#ARG[@]}
,我們發現其實就是在獲取數組全部元素前添加#
來獲取數組個數。
例如:
[root@master scripts]# echo ${#ARG1[*]}
4
[root@master scripts]# echo ${#ARG1[@]}
4
- 獲取單個元素的長度
對于數組中的某個元我們也可以進行長度的獲取,可以利用 ${#ARG1[num]}
。
例如:
[root@master scripts]# echo ${ARG1[@]}
100 2 3 hello Shell 10
[root@master scripts]# echo ${ARG1[3]} //獲取第四個元素內容為:hello Shell
hello Shell
[root@master scripts]# echo ${#ARG1[3]} //獲取四個元素長度為11
11
2.2.4 數組元素的修改
數組可以進行一些列對其元素的操作。
- 修改
對數組元素的修改,直接對單個元素修改即可,例如:
[root@master scripts]# AEG1[0]=100
[root@master scripts]# echo ${ARG1[@]}
100 2 3 hello Shell
- 增加
對數組元素的增加,和修改一致,直接對單個位置元素增加即可,例如:
[root@master scripts]# ARG1[10]=10
[root@master scripts]# echo ${ARG1[@]}
100 2 3 hello Shell 10
[root@master scripts]# echo ${#ARG1[@]}
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[@]}
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
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
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
當然也可以對單個元素進行賦值操作, 我們可以看到關聯數組就沒有排序了,類似于其他語言中的字典,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
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
打印出來的就是最后一列的狀態,我們將其內容作為數組的下標,值為其出現的次數,這樣就可以統計 TCP 鏈接到狀態,配合定時任務來定時統計服務器的 tcp 鏈接狀態。
4.3 實現
[root@master Shell_args]# cat tcp_status.sh
#!/bin/bash
# Description: check tcp status
# Auth: kaliarch
# Email: [email protected]
# 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 的數量為: 138
2020-03-14 15:03 服務器的TCP狀態為: ESTABLISHED 的數量為: 501
2020-03-14 15:03 服務器的TCP狀態為: LISTEN 的數量為: 59
查看我們單獨運行腳本已經成功,可以將這個腳本加入 crontab 中,來定時執行,后期就可以通過日志來查看當時服務器的狀態了。
5. 注意事項
- 需要在實戰中理解數組的具體用途,尤其注意關聯數組的靈活運用;
- 需要理解數組的全部元素,元素下標以及元素的切片和替換,具體場景配合使用;
- 數組一般用來統計批量的內容,例如批量文件的計算等,配合其他命令使用。
6. 小結
數組可謂為我們在 Shell 編程中提供了集合類型數據存儲的方案,對于批量數據的操作,數組功不可沒。在具體的實踐中根據數據特征,明確需求是利用數字作為下標的數組,還是使用關聯數組,最后在實踐中靈活運用數組的整體長度,切片,替換等操作,配合其他命令實現具體業務需求。