摘要:Linux
,Shell
Shell数组类型
Shell数组分为普通数组
和关联数组
,普通数组就是相同类型
的元素组成的以下标
区分的集合,关联数组以key-value
作为区分,类似于其他编程语言的Map结构
数组定义
(1)普通数组
普通数组以整数索引,可以直接定义也可以使用下标定义填充定义,直接定义使用圆括号()
,元素之间用空格隔开
a=(python java scala)
echo ${a[0]} # python
如果元素自带空格,需要用引号括起来
a=(a 'b c' a e)
echo ${a[1]} # b c
填充定义直接起一个变量使用中括号[]
定义下标和值
b[0]=python
b[1]=java
b[2]=scala
echo ${b[@]} # python java scala
(2)关联数组
关联数组也可以直接定义key-value,也可以用空数组填充key-value定义,直接定义之前需要显式声明是关联数组,使用declare -A
,普通数组不需要显式声明,默认创建的就是普通数组,如果要强行显式声明就是declare -a
declare -A c
c=([name]=xiaogp [height]=175 [weight]=70)
echo ${c[height]} # 175
填充定义直接起一个变量使用中括号[]
定义下标key值,在申明和调用key值时可以不使用双引号括起来
declare -A d
d[name]=xiaogp
d[height]=172
d[weight]=70
echo ${d[height]} # 172
也可以写成一行
declare -A e
e[name]=xiaogp;e[height]=175;e[weight]=70
echo ${e[@]} # 175 70 xiaogp
如果一个key被重复指定,则新值会覆盖旧值
map[a]=1
map[a]=2
echo ${map[a]} # 2
(3)从文件中读取定义数组
可以通过cat
,awk
等命令将文件每一行的内容作为一个元素填充到数组,比如
a=(`cat test.txt`)
再看一个文件,使用逗号分隔符记录了一些数据
root@ubuntu:~# head -3 peTTM_rank.txt
2021-07-02,sh.600695,*ST绿庭,2352.677378
2021-07-02,sz.300023,*ST宝德,1803.766121
2021-07-02,sh.600696,ST岩石,904.12449
使用awk选取第二列组成一个数组,将执行结果用圆括号包起来
a=(`awk -F "," '{print $2}' peTTM_rank.txt`)
# 或者a=($(awk -F "," '{print $2}' peTTM_rank.txt))
打印结果如下所有第二列被加入素组中
echo ${a[@]}
sh.600695 sz.300023 sh.600696 sz.000712 sh.600053 sh.600906 sh.603093 sh.601162 sh.600095 sz.300176 sh.601375 sz.000416 sh.601456 sh.601696 sz.300059 sz.000567
echo ${a[0]} # sh.600695
如果要从文件中读取数据组成关联数组需要遍历
#/bin/bash
declare -A map
while read line
do
key=`echo $line |awk -F "," '{print $2}'`
value=`echo $line |awk -F "," '{print $3}'`
map[$key]=$value
done < peTTM_rank.txt
echo ${map[sh.600696]} # ST岩石
(4)数组元素删除
使用unset
删除数组元素或者整个数组
a=('a' 'b' 'z' 'q')
unset a[2]
echo ${a[@]} # a b q
unset a
echo ${a[@]} # 输出空
数组表达式
常见的数组表达式如下
语法 | 描述 |
---|---|
${!array[*]} | 访问数组所有索引(key) |
${!array[@]} | 访问数组所有索引(key) |
${array[*]} | 访问数组所有的值(value) |
$array{@} | 访问数组所有的值(value) |
${#array[@]} | 获得数组元素个数 |
${array[0]} | 获得数组第一个元素 |
${array[@]:1} | 访问数据从下标1开始往后 |
${array[@]:1:2} | 访问数据从下标1开始往后一共2个元素 |
下面做以下简单测试,array[@]和array[*]的区别是当有双引号在外面括起来时,前者是一个一个元素分隔的,后者是一个整体
a=(a b c d e a)
for i in "${a[*]}"; do echo $i; done
a b c d e a
for i in "${a[@]}"; do echo $i; done
a
b
c
d
e
a
测试获取数组长度
echo ${#a[@]} # 6
元素截取,从下标1的元素开始
echo ${a[@]}
a b c d e a
echo ${a[@]:1}
b c d e a
获得数组的key值
declare -A a
a=([name]=xiaogp [age]=13)
echo ${!a[@]} # name age
数据截取和元素替换
数组截取使用数组表达式,格式如下
${array[@]:start:length}
如果第二个冒号后的数字省略则代表取到最后,如果第一个冒号后面的数字省略则代表从第一个元素开始
a=('a' 'b' 'z' 'q' 'z' 'l')
echo ${a[@]:1:3} # 从第二个元素到最后
b z q
echo ${a[@]:1} # 从第二个元素往最后
b z q z l
echo ${a[@]::3} # 第一个元素开始往后3个
a b z
数组元素的修改的格式如下
${array[@]/old/new}
类似于变量替换,但是貌似只支持所有元素替换,不能第一个找到的元素替换,如果要把替换完的数组赋值给一个新数组,必须要加圆括号阔起来
a=('a' 'b' 'a' 'z' 'd')
echo ${a[@]/a/b} # b b b z d
b=(${a[@]/a/b})
echo ${b[@]} # b b b z d
数组遍历
数组遍历采用while循环for循环皆可,while循环用于从文件读取数组
root@ubuntu:~/Shell# cat test.txt
asdsd
wewrer
dcef
while read line
do
array[++i]=$line
done < test.txt
root@ubuntu:~/Shell# echo ${array[@]}
asdsd wewrer dcef
这个效果个直接将cat的结果传给圆括号一致
root@ubuntu:~/Shell# array2=(`cat test.txt`)
root@ubuntu:~/Shell# echo ${array[@]}
asdsd wewrer dcef
(1)普通数组遍历
for循环,从第二个元素开始遍历,使用in
进行遍历
for i in ${a[@]:1}
do
echo $i
done # bc cd de
也可以使用下标进行遍历,先遍历下标,再通过下标获取值
for i in ${!a[@]}
do
echo ${a[i]}
done
也可以类似C语法的循环方法
for ((i=0;i<${#a[@]};i++))
do
echo ${a[i]}
done
也可以复杂一点使用while循环,通过长度判断停止
i=0
while [ $i -lt ${#a[@]} ]
do
echo ${a[i]}
let i++
done
(2)关联数组遍历
关联数组遍历先获得下标再获得值
declare -A a
a=([name]=xiaogp [age]=12 [height]=170)
for i in ${!a[@]}
do
echo ${a[$i]} # 此处要加$引用
done
Shell数组实战
(1)读取文件进行数字统计
文件如下,需要统计第二列的出现次数
root@ubuntu:~/Shell# cat test.txt
xiaogp A
xiaomf C
xiaomk D
xiaosa A
xiaonb C
xiaohy A
xiaone A
xiaopp D
xiaomm A
xiaojh B
统计代码如下
#!/bin/bash
declare -A map
while read line
do
value=`echo $line |awk -F ' ' '{print $2}'`
map[$value]=$[${map[$value]}+1]
done < test.txt
for i in A B C D
do
echo ${i}的出现次数=${map[$i]}
done
运行脚本结果如下
root@ubuntu:~/Shell# bash test.sh
A的出现次数=5
B的出现次数=1
C的出现次数=2
D的出现次数=2