Bash脚本编程学习笔记09:数组
数组简介
在bash脚本编程当中,变量是存储单个元素的内存空间;而数组是存储多个元素的一段连续的内存空间。
数组由数组名和下标构成,如下。
ARRAY_NAME[SUBSCRIPT]
数组按照下标的类型可分为两种:
- 索引(indexed)数组:下标为0、1、2等非负整数。
- 关联(associative)数组:下标为用户自定义的字符串。
数组的操作
声明
索引数组可以不声明直接使用;而关联数组如果不声明直接使用的话,会被认为是索引数组,即使它的下标是字符串。
索引数组的声明方式。
# declare -a ARRAY_NAME
关联数组的声明方式。
# declare -A ARRAY_NAME
赋值
一次只赋值一个元素。
# ARRAY_NAME[SUBSCRIPT]=VALUE
一次赋值全部元素。
# ARRAY_NAME = ("VAL1" "VAL2" "VAL3" ...)
一次赋值多个可以是不连续的元素。
# ARRAY_NAME = ([0] = "VAL1" [3] = "VAL3")
像这种不要求元素必须依次存在的数组(即可以在没有A[1]和A[2]的时候就赋值A[3]),叫做稀疏格式数组。因此,bash支持稀疏格式的数组。
读取标准输入赋值数组。
# read -a ARRAY_NAME
在输入的时候,以空格作为元素的分隔符,以回车键结束元素的赋值。
向数组的末尾追加元素。
ARRAY_NAME[${#ARRAY_NAME[@]}]=VALUE
或者
ARRAY_NAME+=(VALUE)
引用
引用单个数组元素。
${ARRAY_NAME[SUBSCRIPT]}
如果省略SUBSCRIPT,那么就等同于SUBSCRIPT=0。即以下两个引用是相同的。
${ARRAY_NAME[0]} ${ARRAY_NAME}
下标可以是一个变量,当下标是一个变量的时候,可以省略掉展开下标变量字符“$”。即${array[$var]}=${array[var]}。
[root@c7-server ~]# declare -a name=(bu jing yun) [root@c7-server ~]# echo ${name[*]} bu jing yun [root@c7-server ~]# declare -i a=0 b=1 c=2 [root@c7-server ~]# echo ${name[$a]} bu [root@c7-server ~]# echo ${name[$b]} jing [root@c7-server ~]# echo ${name[$c]} yun [root@c7-server ~]# echo ${name[a]} bu [root@c7-server ~]# echo ${name[b]} jing [root@c7-server ~]# echo ${name[c]} yun
引用数组的所有元素。正常情况下,二者没有区别,只有当被双引号包裹的时候,“@”被展开为每个元素为一个独立的单词;“*”被展开为所有元素为一个统一的单词。
${ARRAY_NAME[@]}
${ARRAY_NAME[*]}
引用数组元素的长度。
${#ARRAY_NAME[SUBSCRIPT]}
引用数组的长度,即数组的元素个数。
${#ARRAY_NAME[@]}
${#ARRAY_NAME[*]}
引用数组的部分元素(切片)。
${ARRAY_NAME[@]:OFFSET:NUMBER}
${ARRAY_NAME[*]:OFFSET:NUMBER}
OFFSET:偏移,表示偏移/跳过数组中的前几个元素。
NUMBER:表示偏移后取几个元素。
如果省略了NUMBER,并且OFFSET的值为“ -n”(注意,-n的左边有空格),则表示引用倒数的n个元素。
截止目前我们引用的都是数组的值,如果我们想引用数组的下标的话,可以使用:
${!ARRAY_NAME[@]}
${!ARRAY_NAME[*]}
删除
删除数组元素。
# unset ARRAY_NAME[SUBSCRIPT]
删除数组。
# unset ARRAY_NAME
数组示例
定义一个索引数组,逐一赋值数组元素。
[root@c7-server ~]# declare -a my_array [root@c7-server ~]# my_array[0]=zhang [root@c7-server ~]# my_array[1]=wen [root@c7-server ~]# my_array[2]=long
根据数组下标获取数组元素。留意我们上文说的,当引用数组不带下标的时候,等同于引用${ARRAY_NAME[0]}。
[root@c7-server ~]# echo ${my_array} zhang [root@c7-server ~]# echo ${my_array[0]} zhang [root@c7-server ~]# echo ${my_array[1]} wen [root@c7-server ~]# echo ${my_array[2]}
long
引用数组中的所有元素,顺便测试一下“@”和“*”的区别。注意,这个区别,仅在${my_array[@]}或者${my_array[*]}被双引号包裹的情况下才会出现。
[root@c7-server ~]# echo ${my_array[@]} zhang wen long [root@c7-server ~]# echo ${my_array[*]} zhang wen long [root@c7-server ~]# for i in "${my_array[@]}"; do echo $i; done zhang wen long [root@c7-server ~]# for i in "${my_array[*]}"; do echo $i; done zhang wen long
引用数组个数。
[root@c7-server ~]# echo ${#my_array[@]} 3 [root@c7-server ~]# echo ${#my_array[*]} 3
引用数组中元素的个数。
[root@c7-server ~]# echo ${my_array[0]} zhang [root@c7-server ~]# echo ${#my_array[0]} 5
接下来演示其他几种不同的赋值方式,操作前可先删除数组。
[root@c7-server ~]# unset my_array [root@c7-server ~]# my_array=([0]=zhang [1]=wen [2]=long) [root@c7-server ~]# echo ${my_array[@]} zhang wen long [root@c7-server ~]# unset my_array [root@c7-server ~]# read -a my_array Mon Tue Wed Thu Fri Sat Sun [root@c7-server ~]# echo ${my_array[@]} Mon Tue Wed Thu Fri Sat Sun
数组元素去子串(substring),即切片。
[root@c7-server ~]# echo ${my_array[@]} Mon Tue Wed Thu Fri Sat Sun [root@c7-server ~]# echo ${my_array[@]:3:2} Thu Fri [root@c7-server ~]# echo ${my_array[@]:2:3} Wed Thu Fri [root@c7-server ~]# echo ${my_array[@]: -3} Fri Sat Sun
数组元素追加。
[root@c7-server ~]# echo ${my_array[@]} Mon Tue Wed Thu Fri Sat Sun [root@c7-server ~]# my_array+=(ddd) [root@c7-server ~]# my_array[${#my_array[@]}]=eee [root@c7-server ~]# echo ${my_array[@]} Mon Tue Wed Thu Fri Sat Sun ddd eee
引用数组的下标(subscript)。个人感觉引用数组下标在关联数组中比较有用,在索引数组中用处不大。
[root@c7-server ~]# echo ${!my_array[@]} 0 1 2 3 4 5 6 7 8 [root@c7-server ~]# unset my_array [root@c7-server ~]# declare -A my_array [root@c7-server ~]# my_array=([name]=zwl [age]=28 [sex]=male) [root@c7-server ~]# echo ${my_array[@]} zwl 28 male [root@c7-server ~]# echo ${!my_array[@]} name age sex
练习题
题一:生成10个100以内的非负整数并存入数组当中,对其进行排序然后输出最大值和最小值。
这道题,涉及到算法中的冒泡排序,可以参考一下《冒泡排序_百度百科》中的概念解释,以及《1.1 冒泡排序 | 菜鸟教程》中的图示,这个GIF图真的超棒!
按照升序排序后,最大值和最小值取头尾即可。
代码示例。
#!/bin/bash declare -a rand declare -i rand_length var for i in {0..9}; do rand[$i]=$((RANDOM%100)) done echo -e "The original array is \t${rand[*]}." rand_length=${#rand[*]} #echo $rand_length for i in $(seq 0 $((rand_length-1)) | sort -nr); do for((j=0;j<$i;j++)); do if [ ${rand[j]} -gt ${rand[((j+1))]} ]; then var=${rand[j]} rand[j]=${rand[j+1]} rand[j+1]=$var fi done #echo ${rand[*]} done echo -e "The last array is \t${rand[*]}." echo "The min of the array is ${rand[0]}." echo "The max of the array is ${rand[-1]}."
结果演示。
[root@c7-server ~]# bash arrayBubbleSort.sh The original array is 89 71 5 61 64 81 32 32 44 58. The last array is 5 32 32 44 58 61 64 71 81 89. The min of the array is 5. The max of the array is 89. [root@c7-server ~]# bash arrayBubbleSort.sh The original array is 17 41 81 62 94 97 37 11 11 41. The last array is 11 11 17 37 41 41 62 81 94 97. The min of the array is 11. The max of the array is 97. [root@c7-server ~]# bash arrayBubbleSort.sh The original array is 44 38 38 58 44 36 41 66 85 76. The last array is 36 38 38 41 44 44 58 66 76 85. The min of the array is 36. The max of the array is 85.
看懂代码以后,我们可以调整一下echo语句,就可以看到每次循环排序的结果。
The original array is 57 68 10 50 34 98 52 21 83 36. 57 10 50 34 68 52 21 83 36 98 10 50 34 57 52 21 68 36 83 98 10 34 50 52 21 57 36 68 83 98 10 34 50 21 52 36 57 68 83 98 10 34 21 50 36 52 57 68 83 98 10 21 34 36 50 52 57 68 83 98 10 21 34 36 50 52 57 68 83 98 10 21 34 36 50 52 57 68 83 98 10 21 34 36 50 52 57 68 83 98 10 21 34 36 50 52 57 68 83 98
从结果中我们也会发现,除非是刚好是倒序的情况,否则在循环的中途就可以排序完成了。
这个脚本,个人觉得还是会稍微难点的,尤其是对于算法基础薄弱且非编程的人员,我也是Google后才知道结果的,真的搞不懂的同学,不必纠结,将来再补算法即可,这篇随笔主要是了解数组的。
题二:定义一个数组,数组元素为/var/log/目录下所有以.log结尾的文件的文件名;统计下标为偶数的文件的行数并求和。
#!/bin/bash declare -a filePool=(/var/log/*.log) declare -i sum=0 declare -i line for i in $(seq 0 $((${#filePool[*]}-1))); do if [ $((i%2)) -eq 0 ]; then line=$(wc -l ${filePool[i]} | cut -d " " -f 1) ((sum+=line)) fi done echo "The sum of lines which meet the conditions is $sum."