shell 数组的详细用法

news2024/11/26 3:25:19

简介

    数组是一种数据结构,用于存储和处理一组相关的数据元素。数组可以包含多个值,每个值都有一个索引,用于标识和访问它们。

        

目录

1. 数组的基本用法

1.1. 定义数组的方式

1.1.1. 直接赋值

1.1.2. declare声明数组

1.1.3. 索引赋值

1.1.4. 命令赋值

1.2. 更新数组的方式

1.2.1. 增加数组元素

1.2.2. 修改数组元素

1.2.3. 删除数组元素

1.2.4. 查询数组元素

1.3. 索引切片

1.4. 字母大小写转换

2. 数组的应用

2.1. 连续处理函数

2.2. 定时判断文件大小

2.3. 注意事项


        

1. 数组的基本用法

定义数组的方式类似于定义变量,比如我们定义一个普通变量是这样的:

v="abc"
v=123
v=12ab

数组就是在等于符号后面加上括号,例如:

v=(a b c)
v=(1 2 3)

注意:分隔符默认是空格,这个空格可以是多个空格,也可以tab,只要中间有间隔即可。

         

数组相比于普通变量,数组能存储和访问多个值,在使用过程中也更加的灵活。例如:使用数组和普通变量赋值一个相同的值

variable="Hello World"
array=(Hello World)

普通变量输出方式:

数组可以输出单个值或全部值,这就是数组的优势。

        

1.1. 定义数组的方式

1.1.1. 直接赋值

赋值的对象可以是字符串,可以是数字,也可以是它们的组合,例如:

v=('a' 'b' 'c')
v=(1 2 3)
v=('a' 'b' 1 2)

除了直接赋值,我们也可以通过其他的变量赋值,例如:

n=10
v=('a' 'b' ${n})

         

注意:shell中的数组不涉及深拷贝、浅拷贝的概念,拷贝的方式是对整个数组最新的值进行拷贝。

# 定义2个数组
arr1=(10 20 30)
arr2=('a' 'b' ${arr1[@]})

# 输出这两个数组的结果
echo "两个数组原本的结果:arr1=${arr1[@]}  arr2=${arr2[@]}"

# 修改被拷贝的数组arr1
arr1[1]=50

# 再次输出这两个数组的结果
echo "arr1被修改后的结果:arr1=${arr1[@]}  arr2=${arr2[@]}"

当我们对数组 arr2 赋值数组 arr1 的值后,再修改数组 arr1,这时数组 arr2 也不会发生改变。

如果我们在将 arr1 赋值给 arr2 之前修改值,则 arr2 使用最新的值。例如:

arr1=(10 20 30)

# 修改数组arr1的值
arr1[1]=50

arr2=('a' 'b' ${arr1[@]})

# 输出这两个数组的结果
echo "arr1: ${arr1[@]}"
echo "arr2: ${arr2[@]}"

        

1.1.2. declare声明数组

declare的参数选项

-a:将变量声明为普通数组。
-A:将变量声明为关联数组。
-r:将变量声明为只读(不可修改)。

-i:将变量声明为整数。
-l:将变量的值转换为小写。    #不支持数组
-u:将变量的值转换为大写。    #不支持数组

-f:显示指定函数名的定义,如果不指定函数名,则显示所有函数的定义。用于debug调试
-g:将变量声明为全局变量,使其在函数内外都可访问。
-x:将变量声明为环境变量,可以在 Shell 进程及其子进程中访问。
-x <value>:将变量声明为环境变量,并设置默认值。

        

普通数组和关联数组分别由 -a 和 -A 指定,它们的区别是普通数组使用整数作为索引号,关联数组使用字符串作为索引号(以键值对的方式取值)。例如:

# 普通数组
declare -a arr[0]='abc'
# 关联数组
declare -A arr[a]='abc'

系统默认是普通数组,所以一般不需要使用 -a 指定。关联数组属于特殊数组,需要使用 -A 指定,也可以这样写:

declare -A arr
arr[a1]='abc'
arr[a2]='def'

或者这样写

declare -A arr=([a1]='BBB' [a2]='CCC')

注意:=() 这种方式不能放在后面,否则前面插入的值会被覆盖。

【案例一】先使用索引方式增加值,再使用第2种 =() 的方式

# 定义关联数组
declare -A arr
# 使用索引方式赋值
arr[a1]='abc'
arr[a2]='def'
# 使用括号+键值对方式赋值
arr=([a3]='BBB' [a4]='CCC')
# 输出结果
echo ${arr[@]}

 

a1、a2的值被覆盖

【案例二】我们换一下顺序,将单独插入索引值放在后面

# 定义关联数组
declare -A arr
# 使用括号+键值对方式赋值
arr=([a3]='BBB' [a4]='CCC')
# 使用索引方式赋值
arr[a1]='abc'
arr[a2]='def'
# 输出结果
echo ${arr[@]}

此时前面的值不会被覆盖 

        

注意:当使用 ${arr[@]} 输出整个关联数组时,它会按照 bash 的内部实现来确定元素的顺序,而不是按照插入元素的顺序。

当然了,在实际的用法中我们需要按顺序输出时,一般都是使用普通数组,关联数组一般是用于一些特定的场景,所以不需要关心它的顺序。但是如果这个数组不固定,可能有很多地方存在增加或删除的情况,那么我们需要知道当前数组的键和值如何获取

所有键:${!arr[@]}
所有值:${arr[@]}

例如:

# 定义关联数组
declare -A arr=([a1]='BBB' [a2]='CCC')

# 输出键和值
echo "数组arr的所有键: ${!arr[@]}"
echo "数组arr的所有值: ${arr[@]}"

        

除了声明数组的类型外,还有一些整数的声明方式,例如:

declare -i arr=('abc' 1 2)
echo ${arr[@]}

我们在定义这个变量的时候直接在数组中写入一个字符串,然后得到的结果就是:abc没有被改变 

如果我们写成这样,字符串abc就可以被转换为数字0

declare -i arr
arr=('abc' 1 2)
echo ${arr[@]}

        

我们可以使用declare声明数组整数,却只能声明字符串变量的大小写,不支持数组。这里举2个普通变量的声明大小写方式:

# 声明为小写
declare -l var
var='abC'
echo ${var}

# 声明为大写
declare -u var
var='abC'
echo ${var}

注意:脚本中必须在变量赋值之前声明,如果是在赋值之后声明是无效的。

var='abC'
# 声明为大写
declare -u var
echo ${var}

但如果直接在命令操作的话是有效的

《如果需要将数组的字符串转换为大小写需要将其遍历出来修改。方法见目录2》

        

1.1.3. 索引赋值

默认情况下数组是通过整数索引来访问元素,范围是:0~32767。普通数组不同于关联数组,关联数组使用字符的方式赋值,所以输出整个数组的值对我们来说可能非顺序的;而普通数组输出整个数组时是有序的。例如:

arr=(abc 000 def 123)
echo ${arr[@]}

        

当我们需要对某个位置插入值时,如果这个位置已经有值则直接修改,如果没有则插入。

arr=(abc 000 def 123)
echo "arr原始数据: ${arr[@]}"

# 在索引为1的位置插入或修改值
arr[1]=111
echo "arr修改索引: ${arr[@]}"

        

当代码太多,不知道数组有多少时,我们可以通过追加的方式插入数据

arr=(abc 000 def 123)
echo "原始数据: ${arr[@]}"

# 向数组arr追加元素
arr+=("value1")
arr+=("value2" "value3")
echo "增加数据: ${arr[@]}"

        

1.1.4. 命令赋值

除了手动赋值以外,我们还可以通过Linux命令、函数等方式对数组赋值。

【案例一】直接执行Linux命令对数组赋值

arr=(`ls /home/yt/shell/file`)
echo ${arr[@]}

如果数组中已有数据,那么通过追加的方式赋值

# 定义一些元素到数组
arr=(abc 000)
echo "old_arr: ${arr[@]}"

# 向数组arr追加元素
arr+=(`ls /home/yt/shell/file`)
echo "new_arr: ${arr[@]}"

        

【案例二】通过读取交互输入的值增加到数组

# 定义数组
declare -a arr
# 循环读取交互的值
while read -r line; do
        [ "${line}" == "exit" ] && break
        arr+=("$line")
done
# 输出最终结果
echo "result: ${arr[@]}"

        

【案例三】通过函数结果赋值

# 定义一个函数
func1(){
        echo "123 abc"
        }
# 将函数输出的结果赋值到数组
arr=(`func1`)
# 输出结果
echo "全部的值 : ${arr[@]}"
echo "索引0的值: ${arr[0]}"

对函数来说输出的 "123 abc" 是一个字符串,但中间有一个空格,所以对数组来说是2个值

如果在执行函数加上双引号则对数组来说就是一个值

arr=("`func1`")

注意:函数的返回值无法赋值到数组

​# 定义一个函数
func1(){
        return 1
        }
# 将函数输出的结果赋值到数组
arr=(`func1`)
# 输出结果
echo ${arr[@]}

        

1.2. 更新数组的方式

1.2.1. 增加数组元素

在原数组最后面追加元素

# 原数组
arr=(a b c)
# 向数组中追加新的元素
arr+=(1 2 3)
# 查看结果
echo ${arr[@]}

        
在原数组最前面增加n个元素

# 原数组
arr=(a b c)
# 重新定义数组,在原数组前方增加n个元素
arr=("123" ${arr[@]})
# 查看结果
echo ${arr[@]}

        

按索引增加数组

# 原数组
arr=(a b c)
# 向数组中追加新的元素
arr[3]="d"
# 查看结果
echo ${arr[@]}

        

在索引0和1之间增加一个元素

# 原数组
arr=(1 2 3)
# 切片前半部分和后半部分,然后与新元素进行拼接
arr=(${arr[@]:0:1} "abc" ${arr[@]:1})
# 输出结果
echo ${arr[@]}


         

1.2.2. 修改数组元素

按索引修改元素

# 原数组
arr=(1 2 3)
# 将索引为0的元素修改为100
arr[0]=100
# 输出结果
echo ${arr[@]}

        

按值修改(将元素为3的修改为30)

# 定义一个数组
arr=(1 2 3 4 5)

# 定义需要修改的值和新值
old_value=3
new_value=30

# 遍历数组索引
for i in ${!arr[@]}; do
    # 通过索引查看值,判断该是否为需要修改的值,如果是则修改
	[ "${arr[$i]}" == "${old_value}" ] && arr[$i]=${new_value}
done

# 输出修改后的数组
echo "${arr[@]}"

        

1.2.3. 删除数组元素

  • 删除元素我们通过 unset 去操作
unset 数组名        #删除整个数组
unset 数组名[索引]  #删除数组的某个索引

        

删除整个数组

# 定义一个数组
arr=(1 2 3 4 5)
# 删除这个数组
unset arr
# 输出结果
echo ${arr[@]}

        

按索引删除

# 定义一个数组
arr=(1 2 3 4 5)
# 删除索引为0的元素
unset arr[0]
# 输出结果
echo ${arr[@]}

注意:unset不支持索引切片删除

        

按值删除

# 定义一个数组
arr=(1 2 3 2 4)
# 需要删除的值
unset_value=2

# 便利数组的索引
for i in "${!arr[@]}"; do
    # 如果该索引的值==需要删除的值,则删除
    [ "${arr[$i]}" == "${unset_value}" ] && unset arr[$i]
done

# 输出结果
echo ${arr[@]}

        

1.2.4. 查询数组元素

查询数组的全部元素

echo ${arr[@]}

        

按索引查询某个元素

echo ${arr[0]}    #查看索引为0的元素
echo ${arr[1]}    #查看索引为1的元素

        

查看元素的长度

echo ${#arr[@]}

        

查看元素的索引(从0开始)

echo ${!arr[@]}

        

 过滤出长度为3的元素

arr=("VVVV" "abc" 124 "AA" "===" "ddd")
echo ${arr[@]} |xargs -n 1 |awk 'length($0)==3'

        

1.3. 索引切片

切片的语法如下

${arr[@]:开始索引:向后次数}

查看索引为2后面的全部元素(包括2)

${arr[@]:2}

        

查看索引为2后面3个元素

${arr[@]:2:3}

        

查看前面4个元素

${arr[@]:0:4}

        

查看后面4个元素

${arr[@]:(-4)}

         

查看中间 2~5 元素

${arr[@]:1:4}

        

1.4. 字母大小写转换

 转换大写

arr=("abC" "Def" 1 2 3)

# 使用循环遍历数组,并将每个元素转换为大写
for ((i=0; i<${#arr[@]}; i++)); do
        arr[$i]=${arr[$i]^^}
done

echo "${arr[@]}"

        

转换小写

arr=("abC" "Def" 1 2 3)

# 使用循环遍历数组,并将每个元素转换为小写
for ((i=0; i<${#arr[@]}; i++)); do
        arr[$i]=${arr[$i],,}
done

echo "${arr[@]}"

        

每个单词首字母大写,后面的小写

arr=("abC" "Def" 1 2 3)

# 使用循环遍历数组
for ((i=0; i<${#arr[@]}; i++)); do
    # 读取第1个字符
	firstChar="${arr[$i]:0:1}"
    # 读取第1个以后的字符
	remainingChars="${arr[$i]:1}"
    # 将第一个字符转换为大小,后面的转换为小写
	arr[$i]="${firstChar^^}${remainingChars,,}"
done

echo "${arr[@]}"

        

2. 数组的应用

2.1. 连续处理函数

先来看一个简单的例子

#!/bin/bash

arr=(1 2 3 4 5)

func1() {
    # 参数个数大于0则一直循环
    while [[ $# -gt 0 ]]; do
        local arg="$1"
        if [ ${arg} -eq 1 ];then
            # 在这里添加处理逻辑
            echo "执行任务 1"
        elif [ ${arg} -eq 2 ];then
            # 在这里添加处理逻辑
            echo "执行任务 2"
        elif [ ${arg} -eq 3 ];then
            # 在这里添加处理逻辑
            echo "执行任务 3"
        fi
        shift # 将头部的参数删除
    done
    }
func1 ${arr[@]}

我们通过数组定义了一组值,将这组值传入函数中,函数根据值判断是否执行某个任务。

        

上述可能看不出实际有什么作用,我们带入一个简单的场景,需求如下:

  • 使用最小的代码量封装一个函数用于操作文件,对函数传入的参数顺序执行
#!/bin/bash

arr=(`ls /home/yt/shell/file/*.txt`)

func1() {
    # 参数个数大于0则一直循环
    while [[ $# -gt 0 ]]; do
        local arg="$1"
        if [ -f ${arg} ];then
            # 操作这个文件,例如追加或修改数据
            echo "test" >>${arg}
        fi
        shift # 将头部的参数删除
    done
    }
func1 ${arr[@]}

由于数组可以存储的东西很多,并且在使用的时候我们可以选择式的调用,相对比较方便。

        

2.2. 定时判断文件大小

需求:不确定某个目录下的文件,有时增加、有时删除,需要对所有文件进行监控大小,发生变化后及时提醒。

#!/bin/bash

# 配置需要检查文件的目录
file_path="/home/yt/shell/file"

while true;do
    # 声明一个关联数组
    declare -A arr
    # 将目录下的所有文件放入一个变量
    files="$(find ${file_path} -type f)"

    # 遍历需要检查的文件
    for file in ${files};do
        # 将这些文件大小存储到关联数组中
        arr["${file}"]=$(du -b ${file} |awk '{print $1}')
    done

    # 休眠60s后再次读取文件大小
    sleep 60
    for file in ${files};do
        # 读取文件大小
        size=$(du -b ${file} |awk '{print $1}')
        # 判断与1s前,大小是否发生变化
        if [ ${arr["${file}"]} -ne ${size} ];then
            echo -e "[`date '+%Y-%m-%d %H:%M:%S'`] 文件${file}大小发生变化, 当前${size}byte"
        fi
    done
done

根据需求我们编写一个循环,在循环体中按指定间隔时间不断的的查看文件大小,对比两次查看的大小是否一致。如果文件大小一致则不用预警,如果文件大小不一致则输出预警。

        

2.3. 注意事项

数组在日常中用的比较多,但有些操作可能导致内存增加,比如:

【对大型数组进行排序、过滤、转换等】

array=("大型数组")
# 排序
sorted_array=($(echo "${array[@]}" | tr ' ' '\n' | sort))

如果要对数组进行排序,通常需要将其复制到一个临时数组中,然后对临时数组进行排序,最后将结果复制回原始数组。在排序或复制大型数组时,可能会分配大量的内存。

        

【创建嵌套或多维数组】

arr=( ("数组1") ("数组2") ("数组3") )

如果要处理嵌套或多维数组,通常需要创建多个数组来表示子数组或多维数组。在处理大型、多维或嵌套数组时,可能会占用大量的内存。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1325373.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

山景DU561—32位高性能音频处理器(DSP)芯片

音频处理可以更好地捕捉和处理声音和音乐&#xff1b;而DSP音频处理芯片是一种利用数字信号处理技术进行音频处理的专用芯片&#xff1b;可用于多种应用&#xff0c;从音乐拾音到复杂的音频信号处理&#xff0c;和声音增强。 由工采网代理的山景DU561是一款集成多种音效算法高…

YOLOv5改进 | 卷积篇 | 通过RFAConv重塑空间注意力(深度学习的前沿突破)

一、本文介绍 本文给大家带来的改进机制是RFAConv&#xff0c;全称为Receptive-Field Attention Convolution&#xff0c;是一种全新的空间注意力机制。与传统的空间注意力方法相比&#xff0c;RFAConv能够更有效地处理图像中的细节和复杂模式(适用于所有的检测对象都有一定的…

CentOS安装Python解释,CentOS设置python虚拟环境,linux设置python虚拟环境

一、安装python解释器 1、创建解释器安装的目录&#xff1a;/usr/local/python39 cd /usr/local mkdir python39 2、下载依赖 yum -y install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gcc make libffi-devel xz-devel …

MyBatis——MyBatis的ORM映射和MyBatis的配置文件升级

1.MyBatis的ORM映射 拷贝之前的工程&#xff1a; 1.1.什么是ORM映射 MyBatis只能自动维护库表”列名“与”属性名“相同时的对应关系&#xff0c;二者不同时无法自动ORM&#xff0c;如下&#xff1a; 1.2.列的别名 在SQL中使用 as 为查询字段添加列别名&#xff0c;以匹配…

Gin之GORM事务(转账操作)

禁用默认事务的操作 为了确保数据一致性,GORM 会在事务里执行写入操作(创建、更新、删除)。如果没有这方面的要求,您可以在初始化时禁用它,这将获得大约 30%+ 性能提升。 // 全局禁用 db, err := gorm.Open(sqlite.Open("gorm.db"), &gorm.Config{SkipDef…

CCF编程能力等级认证GESP—C++6级—20230923

CCF编程能力等级认证GESP—C6级—20230923 单选题&#xff08;每题 2 分&#xff0c;共 30 分&#xff09;判断题&#xff08;每题 2 分&#xff0c;共 20 分&#xff09;编程题 (每题 25 分&#xff0c;共 50 分)小杨买饮料小杨的握手问题 答案及解析单选题判断题编程题1编程题…

FAVDICE - Favorite Dice

题意&#xff1a;n个面的骰子&#xff0c;问期望骰多少次可以将所有n个面都骰到 思路&#xff1a;期望dp 状态表示&#xff1a;dp[i]代表已经骰出了i个面&#xff0c;还需要期望骰dp[i]次才能将n个面都骰到 状态转移&#xff1a;对于dp[i]我们考虑两种情况&#xff1a; 1、…

python flask+vue实现前后端图片上传

python flaskvue实现前后端图片上传 vue代码如下&#xff1a; <template><div><input type"file" change"handleFileChange"/><button click"uploadFile">上传</button><br><img :src"imageUrl&…

使用python免费调用Google发布的Gemini双子座大模型API

上期文章,我们介绍了google发布的Gemini双子座大模型,现在google开放了gemini-pro与gemini-pro- vision2个版本的API接口。 其中gemini-pro模型类似与ChatGPT,是一个文本输入输出聊天模型,而vision模型,顾名思义是一个多模态模型,可以支持图片与文本的输入。 我们进入如…

指定每个子字符串长度L将字符串S分割为多个长度最长为L的子字符串textwrap.wrap(s,L)

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 指定每个子字符串长度L 将字符串S分割为多个 长度最长为L的子字符串 textwrap.wrap(s,L) [太阳]选择题 请问以下代码最后输出的结果是&#xff1f; import textwrap a "You are…

OpenCV-9颜色空间的转换

颜色转换API&#xff1a;cvtColor&#xff08;img&#xff0c;colorsapce&#xff09; cvt含义为转换 convesion(转换) 下面为示例代码&#xff1a; import cv2# callback中至少有一个参数 def callback(value):passcv2.namedWindow("color", cv2.WINDOW_NORMAL) …

Python - 深夜数据结构与算法之 Map Set

目录 一.引言 二.Map 与 Set 1.Hash Table 2.Hash Function 3.Hash Collisions 4.Java/Python Code 三.经典算法实战 1.Two-Sum [1] 2.Group-Anagrams [49] 3.Valid-Anagram [242] 四.总结 一.引言 前面介绍了列表 List 及其衍生的栈 Stack 与队列 Queue&#xff0…

SMART PLC MODBUS-RTU通信(多台同一设备通信优化写法)

MODBUS通信基础介绍请查看下面文章链接: https://rxxw-control.blog.csdn.net/article/details/133755924https://rxxw-control.blog.csdn.net/article/details/133755924多台同一设备的MODBUS-RTU通信,我们在编写轮询程序的时候,可以采用站号变址的方式实现。 1、轮询状态…

【漏洞复现】CVE-2023-6895 IP网络对讲广播系统远程命令执行

漏洞描述 杭州海康威视数字技术有限公司IP网络对讲广播系统。 海康威视对讲广播系统3.0.3_20201113_RELEASE(HIK)存在漏洞。它已被宣布为关键。该漏洞影响文件/php/ping.php 的未知代码。使用输入 netstat -ano 操作参数 jsondata[ip] 会导致 os 命令注入。 开发语言:PHP 开…

Java算法(十):【数据结构与算法】之 冒泡排序 详细流程图和源代码实现

冒泡排序 public static void main(String[] LiuJinTao) {// 1、冒泡排序int [] arr {22, 44, 33, 55, 11};for (int i 0; i < arr.length -1; i) {for (int j 0; j < arr.length - 1 - i; j) {if (arr[j] > arr[j 1]) {int temp arr[j];arr[j] arr[j 1];arr[j…

数字图像处理 基于Numpy、PyTorch在频率空间中建模运动模糊

一、简述 运动模糊在图像中很常见,它会降低图像的价值,因为它会破坏图像中包含的数据。在计算机视觉中,通常通过使用许多不同的模糊增强来训练神经网络以适应这种模糊。建模模糊或图像退化的概念来自图像恢复,这是逆转退化影响的过程,以便人类或算法可以辨别原始捕获的数据…

【技术前沿】数字孪生技术助推城市智慧供热:探讨换热站3D可视化的创新之路

换热站作为供热系统不可或缺的一部分&#xff0c;其能源消耗对城市环保至关重要。在双碳目标下&#xff0c;供热企业可通过搭建智慧供热系统&#xff0c;实现供热方式的低碳、高效、智能化&#xff0c;从而减少碳排放和能源浪费。 通过应用物联网、大数据等高新技术&#xff0…

whisper深入-语者分离

文章目录 学习目标&#xff1a;如何使用whisper学习内容一&#xff1a;whisper 转文字1.1 使用whisper.load_model()方法下载&#xff0c;加载1.2 使用实例对文件进行转录1.3 实战 学习内容二&#xff1a;语者分离&#xff08;pyannote.audio&#xff09;pyannote.audio是huggi…

常用的 JSON XML INI CSV 数据格式详解

目录 0 引言1 JSON1.1 数据格式1.2 应用场景 2 XML2.1 数据格式2.2 应用场景 3 INI3.1 数据格式3.2 应用场景 4 CSV4.1 数据格式4.2 应用场景 5 总结 &#x1f64b;‍♂️ 作者&#xff1a;海码007&#x1f4dc; 专栏&#xff1a;C专栏&#x1f4a5; 标题&#xff1a;常用的 XM…