【LinuxShell】Shell编程之数组


一、数组

  数组(Array)是有序的元素序列。若将有限个类型相同的变量的集合命名,那么这个名称为数组名。

  组成数组的各个变量称为数组的分量,也称为数组的元素,有时也称为下标变量。

  用于区分数组的各个元素的数字编号称为下标。元素的下标从0开始。

  数组是在程序设计中,为了处理方便, 把具有相同类型的若干元素按有序的形式组织起来的一种形式。 这些有序排列的同类数据元素的集合称为数组。

二、数组的定义方式

方法一:直接定义参数。

数组名=(value0 value1 value2 ...)

方法二:使用下标值定义每个元素。

数组名=([0]=value [1]=value [2]=value ...)

方法三:先定义一个字符串列表,再引用列表的值定义数组。

列表名="value0 value1 value2 ..."
数组名=($列表名)

方法四:通过下标值,一个一个定义数组内的每个元素。同时也可以通过这种方式修改元素的值。

数组名[0]="value1"
数组名[1]="value2"
数组名[2]="value3"

  其中方法四可以通过for循环来实现一键定义。

三、数组的相关概述

1.数组包括的数据类型

  数值类型== 可以用于定义。

  字符类型:使用" "''定义,防止元素当中有空格,元素按空格分割

2.获取数组长度

echo ${#数组名[*]}  
echo ${#数组名[@]}

例如:

[root@localhost ~]# ary=(10 20 30 40)
[root@localhost ~]# echo ${#ary[*]}
4
[root@localhost ~]# echo ${#ary[@]}
4

3.获取数组数据列表

 echo ${数组名[@]}  
 echo ${数组名[*]}

例如:

[root@localhost ~]# ary=(10 20 30 40)
[root@localhost ~]# echo ${ary[*]}
10 20 30 40
[root@localhost ~]# echo ${ary[@]}
10 20 30 40

  注意:如果只是用普通变量的方式查看的,那么只会显示数组的第一个元素值。

[root@localhost ~]# ary=(10 20 30 40)
[root@localhost ~]# echo ${ary}
10

4.获取数据下标列表

echo ${!数组名[*]}
echo ${!数组名[@]}

例如:

[root@localhost ~]# ary=([1]=20 [0]=30 [3]=40 [4]=30)
[root@localhost ~]# echo ${!ary[*]}
0 1 3 4
[root@localhost ~]# echo ${!ary[@]}
0 1 3 4

5.获取某下标赋值

${数组名[n]}   #n代表元素的下标

例如:

[root@localhost ~]# ary=([1]=20 [0]=30 [3]=40 [4]=30)		#定义ary数组,跳过下标2的定义
[root@localhost ~]# echo ${ary[3]}							#输出ary[3]的值为40
40
[root@localhost ~]# echo ${ary[2]}							#输出ary[2]的值为空

  注意:当定义数组时少定义一个坐标的值,输出结果时查看该下标时,会显示为空。

6.如何判断数组是否缺少元素

方式一:查看最后一个元素值,可以判断数组的下标是否完整,若其中跳过某一些下标,则此方法无法取得最后一个元素值。

[root@localhost ~]# vim demo1.sh
#!/bin/bash 
ary=([1]=20 [0]=10 [3]=40 [4]=30) 							#定义一组数组,其中坐标为2的没有定义
length=${#ary[*]}											#获取ary数组的长度
lastcoordinate=$[length-1]									#获取最后一个元素的坐标
lastelement=${ary[$lastcoordinate]}							#获取最后一个元素的值
curlast=$(echo ${ary[@]} | awk '{print $NF}' )				#通过awk分割来获取输出的最后一个元素的值

echo "ary数组的值为:${ary[*]}"								#输出ary数组的元素值
    
if [ $lastelement -eq $curlast ];then						#判断获取最后一个元素的值与输出最后一个元素的值是否一致
    echo "ary数组是完整的"
else
    echo "ary数组缺少元素"
fi
[root@localhost ~]# bash demo1.sh
ary数组的值为:10 20 40 30
ary数组缺少元素

方式二:通过下标列表来判断是否缺少元素。

[root@localhost ~]# vim demo2.sh
#!/bin/bash
ary=([1]=20 [0]=10 [3]=40 [4]=30)							#定义一组数组,其中坐标为2的没有定义
coordinatenumber=${!ary[*]}									#获取数组的下标列表
length1=$(echo $coordinatenumber | awk '{print $NF}' )		#通过awk分割来获取最后一个坐标的值
length=$[ $length1 + 1 ]									#因为坐标的值是长度-1,所以反向得出数组的长度
length2=${#ary[*]}											#获取数组的实际长度
if [ $length1 -eq $length2 ];then							#判断通过坐标得出的长度与实际数组长度是否一致
echo "ary数组是完整的"
else
    echo "ary数组缺少元素"
fi
[root@localhost ~]# bash demo2.sh
ary数组缺少元素

  其中获取最后一个坐标的方式可以用echo $coordinatenumber | awk '{print $NF}'或者echo {$coordinatenumber##* }两种方式。

方式三:使用数组长度作为下标增加元素用来判断是否缺少元素

[root@localhost ~]# vim demo3.sh
ary=([1]=20 [0]=10 [3]=40 [4]=30)							#定义一组数组,其中坐标为2的没有定义
echo ${ary[@]}												#输出源数组
length=${#ary[@]}											#获取数组长度
ary[length]=70												#在数组最后追加元素
echo ${ary[@]}												#输出现在的数组
[root@localhost ~]# bash demo3.sh							#通过运行脚本可以发现最后一个元素改变了,说明此数组缺少元素
10 20 40 30
10 20 40 70

四、数组的操作

1.数组遍历

[root@localhost ~]# vim demo3.sh
#!/bin/bash
arr1=(10 20 30 40 50 60)
for i in ${arr1[*]}
do 
	echo $i
done
[ root@localhost ~]# bash demo3.sh
10
20
30
40
50
60

  如果想要求一组数组的总和也可以使用该方式来实现

[root@localhost ~]# vim demo3.sh
#!/bin/bash
arr1=(10 20 30 40 50 60)
for i in ${arr1[*]}
do 
	sum=$[sum+i]
done
echo "该数组的总和是 $sum"
[root@localhost ~]# bash demo3.sh
该数组的总和是 210

2.数组切片

${数组名[@或*]:起始位置:长度}

例如:

[root@localhost ~]# ary=(10 20 30 40 50 60)
[root@localhost ~]# echo ${ary[*]}
10 20 30 40 50 60
[root@localhost ~]# echo ${ary[@]:3:1}
40
[root@localhost ~]# echo ${ary[@]:2:3}
30 40 50

3.数组替换

${数组名[*或@]/源参数值/将要替换的参数值}

例如:

[root@localhost ~]# arr=(1 2 3 4 5)
[root@localhost ~]# echo ${arr2[*]/3/66}
1 2 66 4 5
[root@localhost ~]# echo ${arr2[*]}
1 2 3 4 5
echo ${arr2[*}

  以上这种方式只是临时替换的方式,如果想要永久替换可通过()重新赋值实现。例如:

[root@localhost ~]# arr=(1 2 3 4 5)
[root@localhost ~]# echo ${arr2[*]}
1 2 3 4 5
[root@localhost ~]# arr=(${arr[*]/3/66})
[root@localhost ~]# echo ${arr[*]}
1 2 66 4 5

  如果想要替换的字符在数组中匹配有多项,则均都会替换。例如:

[root@localhost ~]# arr=(10 20 30 40 50)
[root@localhost ~]# echo ${arr2[*]}
10 20 30 40 50
[root@localhost ~]# arr=(${arr[*]/0/8})
[root@localhost ~]# echo ${arr[*]}
18 28 38 48 58

4.数组删除

[root@localhost ~]# arr=(1 2 3 4 5)
[root@localhost ~]# unset arr		#删除数组
[root@localhost ~]# echo ${arr[@]}

[root@localhost ~]# arr=(1 2 3 4 5)
[root@localhost ~]# unset arr[2]	#删除第三个元素
[root@localhost ~]# echo ${arr[*]}
1 2 4 5

5.数组追加元素

方法一:使用下标直接赋值增加元素

[root@localhost ~]# ary=(10 20 30 40 50 60)
[root@localhost ~]# echo ${!ary[*]}
0 1 2 3 4 5
[root@localhost ~]# ary[6]=70
[root@localhost ~]# echo ${ary[@]}
10 20 30 40 50 60 70

方法二:使用数组长度作为下标增加元素,这种方式只能用作完整数组。

[root@localhost ~]# ary=(10 20 30 40 50 60)
[root@localhost ~]# echo ${#ary[@]}
6
[root@localhost ~]# ary[${#ary[@]}]=70
[root@localhost ~]# echo ${ary[@]}
10 20 30 40 50 60 70

方法三:直接将源数组放入追加数组的定义列表中

[root@localhost ~]# ary=(10 20 30 40 50 60)
[root@localhost ~]# ary=("${ary[@]}" 70 80 90)
[root@localhost ~]# echo ${ary[@]}
10 20 30 40 50 60 70 80 90

  其中""不能省略,否则,当数组中存在包含空格的元素时会按空格将元素拆分成多个。不能将@替换为*,如果替换为*,不加双引号时与@的表现一致,加双引号时,会将数组array_name中的所有元素作为一个元素添加到数组中。

例如:

[root@localhost ~]# ary=('zhang san' 'li si' 'wang wu')
[root@localhost ~]# echo ${ary[@]}					#从屏幕echo输出结果会误认为6个元素
zhang san li si wang wu
[root@localhost ~]# echo ${!ary[@]}					#实际根据坐标列表查看只有3个元素
0 1 2
[root@localhost ~]# ary1=(${ary[@]})				#如果不加双引号赋值给其他数组
[root@localhost ~]# echo ${#ary1[@]}				#那么经过赋值过后重新输出会有6个元素
6
[root@localhost ~]# ary=('zhang san' 'li si' 'wang wu')
[root@localhost ~]# echo ${ary[@]}					#从屏幕echo输出结果会误认为6个元素
zhang san li si wang wu
[root@localhost ~]# echo ${!ary[@]}					#实际根据坐标列表查看只有3个元素
0 1 2
[root@localhost ~]# ary1=(“${ary[*]}”)				#如果加双引号使用*赋值给其他数组
[root@localhost ~]# echo ${#ary1[@]}				#那么经过赋值过后重新输出只会有一个元素
1

方法四:直接添加需要追加的元素

[root@localhost ~]# ary=(10 20 30 40 50 60)
[root@localhost ~]# echo ${ary[@]}
10 20 30 40 50 60
[root@localhost ~]# ary+=(70 80 90)
[root@localhost ~]# echo ${ary[@]}
10 20 30 40 50 60 70 80 90

  待添加元素必须用"()"包 围起来,并且多个元素用空格分隔。若追加多个参数,此方式效率最高,执行较为方便。

五、函数与数组的使用

1.向函数传数组参数

  如果将数组变量作为函数参数,函数只会取数组变量的第一个值。

[root@localhost ~]# vim demo4.sh
test1(){
	echo "接收到的参数列表:$@"					   #输出test获取到的数组列表
	newarrary=($1)								#获取函数体外后面的第一个位置变量即$array
	echo "新数组的值为:${newarrary[*]}"			#输出重新赋给新变量的数组列表
}
array=(3 2 1 4 5)								#定义一组数组
echo "原始数组的值为:${array[*]}"					#输出原始数组列表
test1 $array									#调用函数以及使用数组作为位置变量
[root@localhost ~]# bash demo4.sh 
原始数组的值为:3 2 1 4 5
接收到的参数列表:3
新数组的值为:3

  解决这个问题则需要将数组变量的值分解成单个的值,然后将这些值作为函数参数使用。在函数内部,再将所有的参数重新组合成一个新的数组变量。

[root@localhost ~]# vim demo4.sh
test1(){
	newarrary=($(echo $@))						#分别获取数组的参数
	echo "新数组的值为:${newarrary[*]}"			#输出新的数组的值
}
array=(3 2 1 4 5)					 	 		#定义一组数组
echo "原始数组的值为:${array[*]}"					#输出原数组的值
test1 ${array[*]}								#调用函数以及使用数组作为位置变量
[root@localhost ~]# bash demo4.sh 
原始数组的值为:3 2 1 4 5
新数组的值为:3 2 1 4 5

  使用$@$#$1查看从数组向函数传参数的结果。

[root@localhost ~]# vim demo4.sh
#!/bin/bash
test1(){
        echo $1
        echo $@
        echo $#
}
arr=(10 20 30 40 50)
test1 ${arr[@]}
[root@localhost ~]# bash demo4.sh 
10												#$1是获取数组的第一个参数的值
10 20 30 40 50									#$@是获取数组的第一个参数的值
5												#$#是获取数组的长度

2.从函数返回数组

[root@localhost ~]# vim demo4.sh
#!/bin/bash
test1(){
	newarrary=($@)								#获取函数体外定义的数组列表值,将newarrary也定义为一个数组
	sum=0										#定义一个获取和的变量
	for value in ${newarrary[*]}				#使用for循环在函数体内的数组列表中取值
	do
		sum=$[$sum + $value]					#将函数体内的数组列表的值进行加法求和
	done
	echo $sum									#输出求和结果
}
array=(10 20 30 40 50)							#定义一组函数
echo "原始数组的值为:${array[*]}"					#输出原始数组的值
result=`test1 ${array[*]}`						#获取函数体内输出的求和结果赋给一个变量
echo "新数组的和为:$result"						#输出变量,变量是求和结果的值
[root@localhost ~]# bash demo4.sh 
原始数组的值为:10 20 30 40 50
新数组的和为:150

六、数组排序算法

1.冒泡排序

  类似气泡上涌的动作,会将数据在数组中从小到大或者从大到小不断地向前移动。

基本思想

  冒泡排序的基本思想是对比相邻的两个元素值,如果满足条件就交换元素值,把较小的元素移动到数组前面,把大的元素移动到数组后面(也就是交换两个元素的位置),这样较小的元素就像气泡一样从底部上升到顶部。

算法思路

  冒泡算法由双层循环实现,其中外部循环用于控制排序轮数,一般为要排序的数组长度减1次,因为最后一次循环只剩下一个数组元素,不需要对比,同时数组已经完成排序,而内部循环主要用于对比数组中每个相邻元素的大小,以确定是否交换位置,对比和交换次数排序轮数而减少。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rNlu5cb4-1683685097420)(C:\Users\86138\AppData\Roaming\Typora\typora-user-images\image-20230510101600649.png)]

具体过程如下

#!/bin/bash
array=(63 4 24 1 3 15)
echo "old_array: ${array[*]}"
length=${#array[*]}
#定义比较轮数,比较轮数为数组长度减1,从1开始
for ((i=1; i<$length; i++))
do
	#确定比较元素的位置,比较相邻两个元素,较大的数往后放,比较次数随比较轮数而减少
	for ((j=0; j<$length-i; j++))
	do
		#定义第一个元素的值
		first=${array[$j]}
		#定义第二个元素的值
		k=$[$j+1]
		second=${array[$k]}
		#比较两个相邻元素的值,如果第一个元素比第二个元素大就互换
		if [ $first -gt $second]
		then
			#把第一个元素值保存到临时变量中
			temp=$first
			#把第二个元素值赋给第一个元素
			array[$j]=$second
			#把临时变量(也就是第一个元素值)赋给第二个元素
			array[$k]=$temp
		fi
	done
done
#输出排序后后的数组
echo "new_arrays: $(array[*])"

2.直接选择排序

  与冒泡排序相比,直接选择排序的交换次数更少,所以速度会快些。

基本思想

  将指定排序位置与其它数组元素分别对比,如果满足条件就交换元素值,注意这里区别冒泡排序,不是交换相邻元素,而是把满足条件的元素与指定的排序位置交换(如从最后一个元素开始排序),这样排序好的位置逐渐扩大,最后整个数组都成为已排序好的格式。

算法思路

  直接排序由双层循环实现,其中外部循环用于控制排序轮数,一般为要排序的数组长度减1次,因为只需要对比到最后一位,最后一位的坐标为长度减1,同时数组已经完成排序。而内部循环主要用于对比当前轮次数组中的最大元素的值,找出对应最大元素的值赋给定义最大元素的下标,最后通过最大元素与当前轮次数组最后一个元素做交换得到由小到大排序的数组。

在这里插入图片描述

具体过程如下

#!/ bin/bash
#定义一组数组
array=(63 4 24 1 3 15)
#获取数组长度
length=${#array[*]}
#定义排序轮数,为数组长度减1,且从1开始
for((i=1; i<$length; i++))
do
	#定义一个每轮循环比较的初始最大元素的下标,从0开始,即第一个元素
	index=0
	#确定用于第一个元素与当前最大元素作比较的索引范围,从1开始,且每轮比较的最后一个元素下标会随着轮数增加而减少
	for ((j=l; j<=$length-i; j++))
	do
		#通过比较获取最大值元素的索引位置
		if [ ${array[$j]} -gt $ {array[$index]} ] ;then
		index=$j
		fi
	done
	#获取每轮最后一个元素的索引
	last=$[$length - $i]
	#把当前轮次的最后一个元素的值保存在临时变量中
	temp=${array[$last]}
	#把最大的元素的值赋给当前轮次的最后一个元素
	array[$last]=${array[$index]}
	#将临时变量的值,即原最后一个元素的值交换
	array[$index]=$temp
done
echo "排序后的数组的值为:${array[@]}"

3.插入排序

  插入排序,又叫直接插入排序。实际中,我们玩扑克牌的时候,就用了插入排序的思想。

基本思想

  在待排序的元素中,假设前n-1个元素已有序,现将第n个元素插入到前面已经排好的序列中,使得前n个元素有序。按照此法对所有元素进行插入,直到整个序列有序。

  但我们并不能确定待排元素中究竟哪一部分是有序的,所以我们一开始只能认为第一个元素是有序的,依次将其后面的元素插入到这个有序序列中来,直到整个序列有序为止。

在这里插入图片描述

具体过程如下

#!/ bin/bash
#定义一组数组
array=(63 4 24 1 3 15)
#获取数组长度
length=${#array[*]}
#定义待排序的元素下标位置
for((i=1; i<$length; i++))
do
	#定义已排好的序列的元素下标位置范围
	for ((j=0; j<=i; j++))
	do
		#将待排序的元素和前面已经排序好的元素依次比较, 较小的数会交换到已排好序列的元素位置,较大的数会放到待排序元素位置
		if [ ${array[$i]} -lt ${array[$j]} ] ;then
			temp=${array[$i]}
			array[$i]=${array[$j]}
			array[$j]=$temp
		fi
	done
done
echo "排序后的数组的值为:${array[@]}"

4.反转排序

  以相反的顺序把原有数组的内容重新排序。

基本思想:

  把数组最后一个元素与第一个元素替换,倒数第二个元素与第二个元素替换,以此类推,直到把所有数组元素反转替换。

具体过程如下

#!/bin/bash
#定义一组数组
array=(10 20 30 40 50 60)
#获取数组长度
length=${#array[*]}
#定义
for ((i=0; i<$length/2; i++))
do
	#定义一个临时变量获取第一个元素的值
	temp=${array[$i]}
	#获取当前轮数的最后一个元素下标,会随着轮数的增加而减少
	last=$[length-$i-1]
	array[$i]=${array[$last]}
	array[$last]=$temp
done
echo "排序后数组的值为:${array[*]}"
  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我的宝贝大唐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值