Shell数组,字典使用
定义数组
A=(a b c def)
| 命令 |
解释 |
结果 |
${A[@]} |
返回数组全部元素 |
a b c def |
${A[*]} |
同上 |
a b c def |
${!A[@]} |
返回全部元素下标位置信息 |
0 1 2 3 |
${!A[*]} |
同上 |
0 1 2 3 |
${#A[@]} |
返回数组元素总个数 |
4 |
${#A[*]} |
同上 |
4 |
${A[0]} |
返回第一个元素 |
a |
${#A[3]} |
返回第4个元素def长度,第一个元素从0开始 |
3 |
A[3]=xyz |
重新设置第4个元素为xyz |
此时返回所有元素为a b c xyz |
A=("${A[@]}" "val") |
数组增加一个元素val |
此时返回所有元素为a b c xyz val |
遍历数组两种方式
A=(a b c xyz val)
-
按序号遍历
| Bash |
|---|
| for i in "${!A[@]}";do
printf "%s\t%s\n" "$i" "${A[$i]}"
done
结果:
0 a
1 b
2 c
3 xyz
4 val
|
-
按数据遍历
| Bash |
|---|
| for i in ${A[*]};do
echo $i
done
结果:
a
b
c
xyz
val
|
定义字典
在 Shell 中,declare 和 typeset 命令在功能上是完全等价的,它们都是 Bash 的内建命令,用于声明变量并设置其属性(如整数、只读、数组、环境变量等)
typeset 命令源自 KornShell (ksh),而 declare 是 Bash 引入的更现代的命名,一般都使用declare
但是我在mac电脑上 bash(低版本) 不支持 declare,反而使用 zsh 的 typeset
常用选项
| 选项 |
含义 |
示例 |
-i name |
声明为整数类型,支持直接算术运算 |
declare -i num=5+3 → num 值为 8 |
-a name |
声明为普通数组 |
declare -a colors=("red" "green" "blue") |
-A name |
声明为关联数组(键为字符串) |
declare -A cap=([china]=beijing [japan]=tokyo) |
-p [name] |
显示变量的属性和值 |
declare -p MY_VAR |
-f [name] |
列出所有自定义函数 |
declare -f |
-F [name] |
仅列出函数名 |
declare -F |
-r name[=value] |
声明为只读变量,不可修改或删除 |
declare -r PI=3.14 |
-x name[=value] |
将变量导出为环境变量 |
declare -x MY_VAR="value" |
-A 定义关联数组并访问
| Bash |
|---|
| # 声明变量dic为字典
declare -A dic
# 按照数组方式定义字典变量
dic=([k1]="v1" [k2]="v2" [k3]="v3")
# 也可以挨个定义
dic[k1]="v1"
dic[k2]="v2"
dic[k3]="v3"
|
具体使用:
可以参照数组方式使用
- 打印k1的值
echo ${dic["k1"]}
输出: v1
- 打印所有value值,使用
* 或者 @ 都可以
echo ${dic[*]}
输出: v1 v3 v2
- 打印所有key,使用
* 或者 @ 都可以
echo ${!dic[*]}
输出: k1 k3 k2
- 添加一个新元素
dic+=([k4]="v4")
查看: echo ${dic["k4"]}
输出: v4
-r 定义只读变量
Shell规定,只读变量生命周期与当前Shell脚本进程相同,且不能消除只读属性和删除只读变量,除非kill当前Shell脚本进程。
-p 显示变量的属性和值
| Bash |
|---|
| $declare -p name
declare -r name="admin"
|
数组,字典结合使用场景
有两个文件:
cat role.ini
| Bash |
|---|
| es=node1,node2,node3
filebeat=node1,node3,node4,node5
logstash=node1
kibana=node1
|
cat host.ini
| Bash |
|---|
| node1=192.168.1.1
node2=192.168.1.2
node3=192.168.1.3
node4=192.168.1.4
node5=192.168.1.5
node6=192.168.1.6
|
- role.ini : 存放应用
角色-节点对应关系
- host.ini : 存放
节点-主机列表
需求:
从 role.ini 和 host.ini 中得到 role - ip 的对应关系
以 role.ini 表中数据为源
示例脚本如下: vim role-ip.sh
| Bash |
|---|
| # 定义三个字典
# role字典;host字典;结果role--ip字典
declare -A IPListDict
declare -A RoleListDict
declare -A RoleIPDict
# 初始化host.ini文件,定义为关联数组 IPListDict
# IPListDict='([node1]="192.168.1.1" [node2]="192.168.1.2" ...)'
function initIPListDict(){
file=$1
# 使用循环定义字典
while read line;do
IPListDict["${line%%=*}"]="${line##*=}"
done < $file
}
# 初始化role.ini文件,定义为关联数组 RoleListDict
# RoleListDict='([es]="node1,node2,node3" [logstash]="node1" ... )'
function initRoleListDict(){
file=$1
# 使用循环定义字典
while read line;do
RoleListDict["${line%%=*}"]="${line##*=}"
done < $file
}
#对于role.ini字典的key循环处理,切割value,作为host.ini中key,得到value并保存
# 遍历角色对应关系的key
function initRoleIPDict(){
for key in $(echo ${!RoleListDict[*]})
do
OLD_IFS="$IFS"
IFS=","
# arr拿到role的key, es logstash ...
arr=(${RoleListDict[$key]})
IFS="$OLD_IFS"
roleallip=""
# 遍历role key
for element in ${arr[@]}
do
# element 的值,es=node1...
element=${IPListDict[$element]}
roleallip=$roleallip$element","
done
# 删除最后一个逗号“,”
roleallip=${roleallip%?}
RoleIPDict[$key]=$roleallip
done
}
hostfile="/root/host.ini"
rolefile="/root/role.ini"
initIPListDict ${hostfile}
initRoleListDict ${rolefile}
initRoleIPDict
# 打印Role-IP结果
for k in "${!RoleIPDict[@]}"
do
echo $k"="${RoleIPDict[$k]}
done
|
脚本输出对应关系:
| Bash |
|---|
| es=192.168.1.1,192.168.1.2,192.168.1.3
logstash=192.168.1.1
kibana=192.168.1.1
filebeat=192.168.1.1,192.168.1.3,192.168.1.4,192.168.1.5
|
脚本中的一些说明
关于字符串的截取,参考Shell脚本字符串截取
比如用到的:
| Bash |
|---|
| # 删除等号之后的所有值
${line%%=*}
# 删除等号之前的所有值
${line##*=}
# 删除最后一个字符,这里是逗号','
${roleallip%?}
|
按照逗号切割字符串,将逗号转为空格,因为shell定界符默认是空格(IFS保存的是shell 默认定界符)
| Bash |
|---|
| # 先保存默认的定界符为OLD_IFS
OLD_IFS="$IFS"
# 重新定义逗号','为新的定界符
IFS=","
# 开始处理需要的数组,将有逗号的值变为了空格,方便循环
arr=(${RoleListDict[$key]})
# 最后处理结束还需要还原默认定界符
IFS="$OLD_IFS"
|
其实也可以使用字符替换的方式处理
| Bash |
|---|
| # node1,node2,node3
arr=(${RoleListDict[$key]})
# 将逗号','换成空格' ',注意大括号中最后有空格
echo ${arr//,/ }
输出: `node1 node2 node3`
|