[转帖]Bash脚本编程学习笔记09:数组

bash,脚本,编程,学习,笔记,数组 · 浏览次数 : 0

小编点评

**题一:定义数组** ```bash declare -a filePool=(/var/log/*.log) ``` **题二:统计文件的行数并求和** ```bash declare -i sum=0 declare -i linefor i in $(seq 0 $((${#filePool[*]}-1))); do if [ $((i%2)) -eq 0 ]; then line=$(wc -l ${filePool[i]} | cut -d \" \" -f 1) ((sum+=line)) fidone echo \"The sum of lines which meet the conditions is $sum.\" ``` **排版:** ``` The sum of lines which meet the conditions is 1024. ```

正文

https://www.cnblogs.com/alongdidi/p/bash_array.html

 

数组简介

在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."

与[转帖]Bash脚本编程学习笔记09:数组相似的内容:

[转帖]Bash脚本编程学习笔记09:数组

https://www.cnblogs.com/alongdidi/p/bash_array.html 数组简介 在bash脚本编程当中,变量是存储单个元素的内存空间;而数组是存储多个元素的一段连续的内存空间。 数组由数组名和下标构成,如下。 ARRAY_NAME[SUBSCRIPT] 数组按照下标

[转帖]Bash脚本编程学习笔记02:脚本基础和bash配置文件

脚本基础 参考资料:Shell Scripts (Bash Reference Manual) 不严谨地说,编程语言根据代码运行的方式,可以分为两种方式: 编译运行:需要先将人类可识别的代码文件编译成机器可运行的二进制程序文件后,方可运行。例如C语言和Java语言。 解释运行:需要一个编程语言的解释

[转帖]Bash脚本编程学习笔记03:算术运算

https://www.cnblogs.com/alongdidi/p/bash_arithmetic_expression.html 简介 Bash所支持的算术运算和C语言是一样的,这里指的是操作符(operator)以及它们的优先级(precedence)、结合性(associativity)和

[转帖]Bash脚本编程学习笔记04:测试命令test、状态返回值、位置参数和特殊变量

Bash脚本编程学习笔记04:测试命令test、状态返回值、位置参数和特殊变量 我自己接触Linux主要是大学学习的Turbolinux --> 根据《鸟哥的Linux私房菜:基础篇》(第三版) --> 马哥的就业班课程。给我的感觉是这些课程对于bash的讲解,理论上是不够的,但是限于时间、篇幅和精

[转帖]Bash脚本编程学习笔记04:测试命令test、状态返回值、位置参数和特殊变量

https://www.cnblogs.com/alongdidi/p/test_exitStatus_positionalAndSpecialParameter.html 我自己接触Linux主要是大学学习的Turbolinux --> 根据《鸟哥的Linux私房菜:基础篇》(第三版) --> 马

[转帖]Bash脚本编程学习笔记03:算术运算

https://www.cnblogs.com/alongdidi/p/bash_arithmetic_expression.html 简介 Bash所支持的算术运算和C语言是一样的,这里指的是操作符(operator)以及它们的优先级(precedence)、结合性(associativity)和

[转帖]Bash脚本编程学习笔记05:用户交互与脚本调试

https://www.cnblogs.com/alongdidi/p/read_and_bash_debug.html 用户交互 在《学习笔记04》中我们有提到位置参数,位置参数是用来向脚本传递参数的一种方式。还有一种方式,是read命令。 [root@c7-server ~]# read nam

[转帖]Bash脚本编程学习笔记06:条件结构体

简介 在bash脚本编程中,条件结构体使用if语句和case语句两种句式。 if语句 单分支if语句 if TEST; then CMD fi TEST:条件判断,多数情况下可使用test命令来实现,返回值为0的话则执行CMD,否则就离开该条件结构体,脚本继续往下执行。 [root@c7-serve

[转帖]Bash脚本编程学习笔记07:循环结构体

https://www.cnblogs.com/alongdidi/p/bash_loop_construct.html 本篇中涉及到算术运算,使用了$[]这种我未在官方手册中见到的用法,但是确实可用的,在此前的博文《Bash脚本编程学习笔记03:算术运算》中我有说明不要使用,不过自己忘记了。大家还

[转帖]Bash脚本编程学习笔记08:函数

https://www.cnblogs.com/alongdidi/p/bash_function.html 官方资料:Shell Functions (Bash Reference Manual) 简介 正如我们在《Bash脚本编程学习笔记06:条件结构体》中最后所说的,我们应该把一些可能反复执行