Shell编程:一篇讲透数组全知识点

2024-09-02 02:36

本文主要是介绍Shell编程:一篇讲透数组全知识点,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!


文章目录

  • 数组
    • 数组参数的使用 $* $@ $#
    • 数组展开示例
    • 数组定义方法
    • 数组包含的数据类型
    • 获取数组长度
    • 读取特定索引的值
    • 数组遍历
    • 数组切片
    • 数组替换
    • 删除数组
    • 追加数组元素
    • 插入数组元素
    • 向函数传递数组参数


数组

在 Bash 脚本中,数组是一种存储多个元素的变量结构,可以使用不同的方式定义和操作数组。

例如,定义数组 arr 并为其分配初始值:

arr=(30 20 10 60)  # 数组中的元素值

在这个数组中:

  • 30 为索引 0
  • 20 为索引 1
  • 10 为索引 2
  • 60 为索引 3

注意:数组的索引从 0 开始,这和大多数编程语言一致。

数组参数的使用 $* $@ $#

如果在数组中有三个参数 1 2 3,运行数组脚本后:

  • "$*" 代表 "1 2 3" (作为一个整体使用)
  • "$@" 代表 "1" "2" "3" (分别作为单个的个体使用)
  • "$#" 表示参数的数量,即 3

数组展开示例

定义一个简单的数组:

arr=("a" "b" "c")

使用 *@ 进行数组展开的对比:

echo "使用 \\"${arr[*]}\\" 进行展开:"
for item in "${arr[*]}"; doecho $item
doneecho "使用 \\"${arr[@]}\\" 进行展开:"
for item in ${arr[@]}; doecho $item
done

数组定义方法

方法一:直接定义

数组名=(value0 value1 value2 …)

示例:

arr=(1 2 3 4 5)
echo ${arr[*]}  # 输出:1 2 3 4 5

方法二:指定索引

数组名=([索引]=value [索引]=value …)

示例:

arr=([0]=1 [1]=2 [2]=3)
echo ${arr[*]}  # 输出:1 2 3

方法三:引用变量列表

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

示例:

list="1 2 3 4" # 以空格为分隔的列表
arr2=($list)
echo ${arr2[*]}  # 输出:1 2 3 4

方法四:逐个赋值

数组名[索引]=value

示例:

arr3[0]="1"
arr3[1]="2"
arr3[2]="3"
echo ${arr3[*]}  # 输出:1 2 3

数组包含的数据类型

数组中的数据类型可以是:

  • 数值类型
  • 字符类型

字符类型需要使用双引号 " " 或单引号 ' ' 进行定义。

获取数组长度

使用 ${#数组名[*]} 可以获取数组的长度,即数组中元素的总数。

arr1=(1 2 3 4 5)
echo ${#arr1[*]}  # 输出:5

读取特定索引的值

可以通过指定索引来获取数组中的元素值:

arr1=(1 2 3 4 5)
echo ${arr1[0]}  # 输出:1
echo ${arr1[3]}  # 输出:4echo ${arr1[*]}  # 输出整个数组

索引为空值的情况

若某一索引为空值,使用 ${arr[*]} 查看不到这个空值,会依次查看后面的索引内容,但是读取特定索引(该空值)是可以看到是空值,查看数组长度 ${#arr1[*]} 也可以看到总长度。因此尽可能不放空值。

arr1=("10" "20" " " "30")
echo ${#arr1[*]}
4         # 输出长度
echo ${arr1[*]}
10 20 30  # 输出整个数组
echo ${arr1[2]}# 输出为空,因为这个索引内容为空值

数组遍历

使用 for 循环遍历数组元素:

arr5=(1 2 3 4 5)
for i in ${arr5[*]}  # 或 for i in ${arr5[@]}
doecho $i
done

数组切片

可以使用切片来获取数组的一部分元素,即以某一位为起始往后取几位:

arr1=(1 2 3 4 5)
echo ${arr1[*]:0:2}  # 输出:1 2
echo ${arr1[*]:2:2}  # 输出:3 4

数组替换

可以使用替换功能对数组的元素进行临时或永久的替换:

arr1=(1 2 3 4 5)
echo ${arr1[*]/4/66}  # 临时替换# 输出:1 2 3 66 5
arr1=(${arr1[*]/4/66})  # 永久替换
echo ${arr1[*]}         # 输出:1 2 3 66 5

删除数组

使用 unset 命令删除整个数组或特定索引的元素:

unset arr1     # 删除整个数组
unset arr1[2]  # 删除索引为2的元素

追加数组元素

追加新元素到数组的几种方法:

方法一:直接指定索引

arr1=(1 2 3 4 5)
arr1[5]=6  # 原数组只有5位,追加在第6位

方法二:使用数组长度作为索引

当数组的元素非常多的时候,可以直接使用数组的长度作为将要追加的索引的值。

因为原始数组的索引是从0开始的,所以用长度减去1就是原始数组的最后的以为索引值了,

那么将要添加的值应该是原始索引值的后一位,那显然就等于数组的长度值了。

arr1[${#arr1[*]}]=7

方法三:使用现有数组追加新元素

双引号不能省略,否则,当数组arr1中存在包含空格的元素时会按空格将元素拆分成多个。

不能将@替换为*,如果替换为*,不加双引号时与@的表现一致,加双引号时,会将数组arr1中的所有元素作为一个元素添加到数组中。

简单理解:用*号是作为一个整体,而用@还是单个的个体。

arr1=(1 2 3 4 5)
echo ${arr1[*]}
# 输出:1 2 3 4 5
arr1=("${arr1[@]}" 6 7 8) # 用@可以不加引号,最好不加
echo ${arr1[*]}
# 输出:1 2 3 4 5 6 7 8# 再如
abc1=(1 2 3 4 5)
echo ${abc1[*]}
# 输出:1 2 3 4 5
abc1=("${abc1[*]}" 6 7 8)
echo ${abc1[*]}
# 输出:1 2 3 4 5 6 7 8

拓展:遍历元素输出

for i in ${arr1[*]}
> do
> echo $i
> done
1
2
3
4
5
6
7
8
# 再如
for i in "${abc1[@]}";do echo $i;done
1 2 3 4 5

方法四:使用 += 操作符

待添加元素必须用“()"包围起来,并且多个元素用空格分隔。

arr1=(1 2 3 4 5)
echo ${arr1[*]}
# 输出:1 2 3 4 5
arr1+=(11 22)        # 此处追加
echo ${arr1[*]}
# 输出:1 2 3 4 5 11 22

插入数组元素

在数组 arr 的指定位置插入一个新元素,在 arr[4] 的位置插入数字 5

方法一:直接插入

#!/bin/bash# 定义初始数组
arr=(1 2 3 4 6 7)# 在 arr[4] 位置插入数字 5
arr=("${arr[@]:0:4}" 5 "${arr[@]:4}")# 输出结果
echo "插入后的数组为:${arr[*]}"# 输出:插入后的数组为:1 2 3 4 5 6 7

方法二:使用for循环

依次循环赋值元素到新数组,遇到待插入的元素先赋值新元素

#!/bin/bash# 定义初始数组
arr=(1 2 3 4 6 7)# 新数组
new_arr=()# 指定插入位置
insert_position=4
# 要插入的值
insert_value=5# 使用for循环遍历原数组并插入新值
for ((i = 0; i < ${#arr[@]}; i++)); do# 如果当前索引是插入位置if [ $i -eq $insert_position ]; thennew_arr+=("$insert_value")  # 插入新值fi# 插入原数组的元素new_arr+=("${arr[i]}")
done# 如果插入位置超出了数组的末尾,将新值添加到最后
if [ $insert_position -ge ${#arr[@]} ]; thennew_arr+=("$insert_value")
fi# 输出结果
echo "插入后的数组为:${new_arr[*]}"# 输出:插入后的数组为:1 2 3 4 5 6 7

方法三:使用换位的逻辑

后移腾出新位置,新元素直接插入到新位置

#!/bin/bash# 定义初始数组
arr=(1 2 3 4 6 7)# 指定插入位置
insert_position=4
# 要插入的值
insert_value=5# 扩展数组大小,将最后一个元素再添加一次
arr+=("${arr[-1]}")# 使用for循环从后往前移动元素,为插入的新元素腾出位置
for ((i=${#arr[@]}-2; i>=insert_position; i--)); doarr[$((i + 1))]=${arr[$i]}
done# 在指定位置插入新元素
arr[$insert_position]=$insert_value# 输出结果
echo "插入后的数组为:${arr[*]}"# 输出:插入后的数组为:1 2 3 4 5 6 7

向函数传递数组参数

  1. (缺陷)直接传递整个数组变量

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

#!/bin/bash
test1 () {echo "接收到的参数列表:$@"abc2=$1echo "新数组的值为:${abc2[*]}"
}abc=(3 2 1 4 5)
test1 $abc
#将数组变量作为函数的参数,只会取数组变量的第一个值

执行结果:

[root@loaclhost shuzu1]#chmod +x b.sh 
[root@loaclhost shuzu1]#./b.sh 
原始数组的值为:3 2 1 4 5
接受到的参数列表:3
新数组的值为:3 
  1. (解决方法)将数组元素拆分为单个参数

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

#!/bin/bash
test2 () {abc1=($(echo $@))  # 或者表示为 abc1=(`echo $@`)echo "新数组的值为:${abc1[*]}"
}abc=(`seq 1 10`)
test2 ${abc[*]}     # 将数组的值分解为单个的值

执行结果:

[root@loaclhost shuzu1]#chmod +x c.sh 
[root@loaclhost shuzu1]#./c.sh 
新数组的值为:1 2 3 4 5 6 7 8 9 10
  1. 从函数返回数组:数组元素运算

    示例1:加法传参运算

    #!/bin/bash
    test2 () {abc1=(`echo $@`)sum=0for i in ${abc1[*]}dosum=$((sum + i)) # 或sum=$[$sum + $i]doneecho "$sum"
    }abc=(3 2 1 4 5)
    test2 ${abc[*]}  # 输出数组元素的和
    

    执行结果:

    [root@localhost shuzu1]# ./c.sh
    15
    

    示例2:乘法传参运算

    #!/bin/bash
    test3 () {abc1=(`echo $@`)#for ((i=0; i<$#; i++))  # $#为参数的个数for ((i=0; i<=$[$# - 1]; i++))# $#是原始数组的元素个数,这里取出新数组的索引值,不减的话就是一个字符串doabc1[$i]=$((abc1[$i] * 2))  # 每个元素乘以2# 将每个原始索引对应的元素值乘以2传到新的数组中对应的索引的元素中去doneecho "${abc1[*]}"   # 输出新数组
    }abc=(1 2 3)
    test3 ${abc[*]}  
    

    执行结果:

    [root@localhost shuzu1]# ./c.sh
    2 4 6
    

这篇关于Shell编程:一篇讲透数组全知识点的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1128752

相关文章

基本知识点

1、c++的输入加上ios::sync_with_stdio(false);  等价于 c的输入,读取速度会加快(但是在字符串的题里面和容易出现问题) 2、lower_bound()和upper_bound() iterator lower_bound( const key_type &key ): 返回一个迭代器,指向键值>= key的第一个元素。 iterator upper_bou

hdu2241(二分+合并数组)

题意:判断是否存在a+b+c = x,a,b,c分别属于集合A,B,C 如果用暴力会超时,所以这里用到了数组合并,将b,c数组合并成d,d数组存的是b,c数组元素的和,然后对d数组进行二分就可以了 代码如下(附注释): #include<iostream>#include<algorithm>#include<cstring>#include<stack>#include<que

Linux 网络编程 --- 应用层

一、自定义协议和序列化反序列化 代码: 序列化反序列化实现网络版本计算器 二、HTTP协议 1、谈两个简单的预备知识 https://www.baidu.com/ --- 域名 --- 域名解析 --- IP地址 http的端口号为80端口,https的端口号为443 url为统一资源定位符。CSDNhttps://mp.csdn.net/mp_blog/creation/editor

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal

hdu 1166 敌兵布阵(树状数组 or 线段树)

题意是求一个线段的和,在线段上可以进行加减的修改。 树状数组的模板题。 代码: #include <stdio.h>#include <string.h>const int maxn = 50000 + 1;int c[maxn];int n;int lowbit(int x){return x & -x;}void add(int x, int num){while

【编程底层思考】垃圾收集机制,GC算法,垃圾收集器类型概述

Java的垃圾收集(Garbage Collection,GC)机制是Java语言的一大特色,它负责自动管理内存的回收,释放不再使用的对象所占用的内存。以下是对Java垃圾收集机制的详细介绍: 一、垃圾收集机制概述: 对象存活判断:垃圾收集器定期检查堆内存中的对象,判断哪些对象是“垃圾”,即不再被任何引用链直接或间接引用的对象。内存回收:将判断为垃圾的对象占用的内存进行回收,以便重新使用。

Go Playground 在线编程环境

For all examples in this and the next chapter, we will use Go Playground. Go Playground represents a web service that can run programs written in Go. It can be opened in a web browser using the follow

深入理解RxJava:响应式编程的现代方式

在当今的软件开发世界中,异步编程和事件驱动的架构变得越来越重要。RxJava,作为响应式编程(Reactive Programming)的一个流行库,为Java和Android开发者提供了一种强大的方式来处理异步任务和事件流。本文将深入探讨RxJava的核心概念、优势以及如何在实际项目中应用它。 文章目录 💯 什么是RxJava?💯 响应式编程的优势💯 RxJava的核心概念

两个月冲刺软考——访问位与修改位的题型(淘汰哪一页);内聚的类型;关于码制的知识点;地址映射的相关内容

1.访问位与修改位的题型(淘汰哪一页) 访问位:为1时表示在内存期间被访问过,为0时表示未被访问;修改位:为1时表示该页面自从被装入内存后被修改过,为0时表示未修改过。 置换页面时,最先置换访问位和修改位为00的,其次是01(没被访问但被修改过)的,之后是10(被访问了但没被修改过),最后是11。 2.内聚的类型 功能内聚:完成一个单一功能,各个部分协同工作,缺一不可。 顺序内聚:

函数式编程思想

我们经常会用到各种各样的编程思想,例如面向过程、面向对象。不过笔者在该博客简单介绍一下函数式编程思想. 如果对函数式编程思想进行概括,就是f(x) = na(x) , y=uf(x)…至于其他的编程思想,可能是y=a(x)+b(x)+c(x)…,也有可能是y=f(x)=f(x)/a + f(x)/b+f(x)/c… 面向过程的指令式编程 面向过程,简单理解就是y=a(x)+b(x)+c(x)