1. 数组简介

1. 数组简介

  1. 变量:存储单个元素的内存空间
  2. 数组:存储多个元素的连续的内存空间,相当于多个变量的集合
  3. 数组名和索引
    索引:编号从0开始,属于数值索引
    • 注意:索引可支持使用自定义的格式,而不仅是数值格式,即为关联索引,从bash4.0版本之后开始支持

2. 声明数组:

数组的作用范围

数组其实也是属于变量,只不过是变量的合集;因子数组也分为环境数组,普通数组以及局部数组

声明普通数组

declare -a ARRAY_NAME(普通数组):可以不用先声明,直接使用即可

declare -A ARRAY_NAME(关联数组):必须先声明才可以使用,如果先使用了(相当于是一个普通数组),必须unset之后再重新声明为关联数组才可以使用

  • 注意:两者不可相互转换,下同

声明环境数组

declare -xa ARRAY_NAME(普通数组):可以不用先声明,直接使用即可

declare -xA ARRAY_NAME(关联数组):必须先声明才可以使用,如果先使用了(相当于是一个普通数组),必须unset之后再重新声明为关联数组才可以使用

声明局部数组(只能在函数中使用)

local [-a] ARRAY_NAME(普通数组):可以不用先声明,直接使用即可

local -A ARRAY_NAME(关联数组):必须先声明才可以使用,如果先使用了(相当于是一个普通数组),必须unset之后再重新声明为关联数组才可以使用

3. 数组注意点:

  1. bash的数组支持稀疏格式(索引不连续),非常实用,但是要注意稀疏格式的数组总个数就是有元素的个数,而不是数组的下标的最大值的个数
  2. 注意单个字符串(也就是变量名)取其中字符串长度的时候不需要加下标${#varialble}(也可以加上下标为0,也就是{#varialble[0]}),同时字符串想要取中间的部分字符,只能用${var:#:#}的这种方式,因为var它就相当于数组只有一个元素它本身(或者说这个字符串开头的地址var[0])
    • 单个字符串(也就是变量)如果${#varialble[*]}则结果是1,因为它可以看做是一个只有一个元素的数组,其中的元素就是这个字符串。
    • 只有包含多个元素(字符串)的数组,取其中一个元素(字符串)长度的时候才加下标${#array[下标数]}
  3. 而数组中的每个元素中内容想要切片的话则要加上下标${array[INDEX]:#:#},(此时就是把这个带下标的数组元素名当做一个地址,看作是本身的下标0了)。取数组中的各个元素的话则是${array[*|@]:#:#}的方式。
  4. 不写下标默认其为0
    • 因此字符串(也就是变量),当不写下标的时候就是代表整个字符串
    • 而数组中如果不写下标就是代表这个数组里面的第一个元素。
# abc=12334 # echo ${abc[0]} 12334 # echo ${abc} 12334 # echo ${#abc} 5 # array=([1]=12wad [5]=ff [6]=cvv [8]=1wd234) # echo $array # echo ${array[0]} # echo ${array[1]} 12wad # echo ${#array[1]} :第一个元素的长度 5 # echo ${#array[*]} :数组总长度,稀疏数组只看有几个元素就是几 4 # echo ${array[1]:2:3} :第一个元素内容切片 wad # echo ${array[*]} 12wad ff cvv 1wd234 # echo ${array[*]:2:2} :取不同的数组元素,注意和元素内容切片的区分 ff cvv # echo ${array[*]:2:3} ff cvv 1wd234

4. 数组赋值

4.1. 数组元素的赋值

  1. 一次只赋值一个元素
    ARRAY_NAME[INDEX]=VALUE weekdays[0]="Sunday" weekdays[4]="Thursday"
  2. 一次赋值全部元素(注意尽量要加上引号,虽然空格也可以作为分隔符)
    ARRAY_NAME=("VAL1" "VAL2" "VAL3" ...)
  3. 只赋值特定元素
    ARRAY_NAME=([0]="VAL1" [3]="VAL2" ...)
  4. 交互式数组值对赋值(注意有一个-a的选项)
    read -a ARRAY
  • 显示所有数组:
    declare -a

4.2. 特殊的赋值方式:

num=({1..10}) :1到10赋值给num[0]num[9]

file=(*.sh) :当前目录中sh后缀的文件名赋值给file数组

4.3. 稀疏方式赋值注意点:

如果先一个一个赋值,然后又一次赋值特定元素(3中的方式),就算赋值的元素下标并不一样,但这样仍然则会将一个一个赋值的结果给覆盖掉(没赋值到的元素则为空,其实这也就是相当于全覆盖了整个数组,相当于之前一个一个赋值的所有内容全部被清除了,3中方式赋值后整个数组就是个新的数组了)

但是反过来如果先一次性赋值(3中的方式),然后再一个一个赋值下标不同的数组元素,则不会覆盖掉一次性赋值的元素

4.3.1. 比如说:

19:40[root@centos7 /data]# testarray[2]=12 19:40[root@centos7 /data]# testarray[5]=1234 19:40[root@centos7 /data]# echo ${testarray[2]} 12 19:40[root@centos7 /data]# declare -a declare -a testarray='( [2]="12" [5]="1234")' 19:40[root@centos7 /data]# testarray=( [1]=wade [3]=waef ) 19:40[root@centos7 /data]# echo ${testarray[2]} 19:40[root@centos7 /data]# declare -a declare -a testarray='([1]="wade" [3]="waef")' 上面会覆盖,然后继续,下面的不会覆盖: 19:40[root@centos7 /data]# testarray[2]=12 19:44[root@centos7 /data]# testarray[5]=1234 19:44[root@centos7 /data]# declare -a declare -a testarray='([1]="wade" [2]="12" [3]="waef" [5]="1234")'

5. 数组数据处理

5.1. 引用数组

  1. 引用数组元素

    • 注意:省略[INDEX]表示引用下标为0的元素
    ${ARRAY_NAME[INDEX]}
  2. 引用数组所有元素

    ${ARRAY_NAME[*]} ${ARRAY_NAME[@]}
  3. 数组的长度(数组中元素的个数)

    ${#ARRAY_NAME[*]} ${#ARRAY_NAME[@]}
  4. 删除数组中的某元素:导致稀疏格式

    unset ARRAY[INDEX]
  5. 删除整个数组

    • 类似的还有删除变量,删除函数,注意都是从内存中删除掉
    unset ARRAY

5.2. 引用数组中的元素:

  1. 数组切片:
    ${ARRAY[*]:offset:number} offset 要跳过的元素个数 number 要取出的元素个数
  2. 取偏移量之后的所有元素
    ${ARRAY[*]:offset}
  3. 向数组中追加元素(因为下标从0开始):
    ARRAY[${#ARRAY[*]}]=value
  4. 关联数组:
    • 注意:关联数组必须先声明再调用
    declare -A ARRAY_NAME ARRAY_NAME=([idx_name1]='val1' [idx_name2]='val2'...)

5.3. 示例

  1. 生成10个随机数保存于数组中,并找出其最大值和最小值
    • (优化算法:不要每次都判断是否是第一个,把第一个赋值写在for循环外面,然后for循环直接从1开始即可)
#!/bin/bash declare -i min max declare -a nums for ((i=0;i<10;i++));do nums[$i]=$RANDOM [ $i -eq 0 ] && min=${nums[$i]} && max=${nums[$i]} && continue [ ${nums[$i]} -gt $max ] && max=${nums[$i]} [ ${nums[$i]} -lt $min ] && min=${nums[$i]} done echo “All numbers are ${nums[*]}” echo Max is $max echo Min is $min
  1. 编写脚本,定义一个数组,数组中的元素对应的值是/var/log目录下所有以.log结尾的文件;

    统计出其下标为偶数的文件中的行数之和

#!/bin/bash # declare -a files files=(/var/log/*.log) declare -i lines=0 for i in $(seq 0 $[${#files[*]}-1]); do if [ $[$i%2] -eq 0 ];then let lines+=$(wc -l ${files[$i]} | cut -d' ' -f1) fi done echo "Lines: $lines."

6. 字符串处理

6.1. 字符串切片

  1. ${#var}
    • 返回字符串变量var的长度
  2. ${var:offset}
    • 返回字符串变量var中从第offset个字符后(不包括第offset个字符)的字符开始,到最后的部分,offset的取值在0 到 ${#var}-1 之间 (bash4.2后,允许为负值)
  3. ${var:offset:number}
    • 返回字符串变量var中从第offset个字符后(不包括第offset个字符)的字符开始,长度为number的部分
  4. ${var: -length}
    • 取字符串的最右侧几个字符
      • 注意:冒号后必须有一空白字符
  5. ${var:offset:-length}
    • 从最左侧跳过offset字符,一直向右取到距离最右侧lengh个字符之前的内容
  6. ${var: -length:-offset}
    • 先从最右侧向左取到length个字符开始,再向右取到距离最右侧offset个字符之间的内容
      • 注意:-length前有空格(中间的那个必须有空格,:最后的一项可以不加空格)

6.2. 引用字符串

  1. ${var#*word}:其中word可以是指定的任意字符

    • 功能:自左而右,查找var变量所存储的字符串中,第一次出现的word, 删除字符串开头至第一次出现word字符串(含)之间的所有字符
  2. ${var##*word}:同上,贪婪模式,

    • 不同的是,删除的是字符串开头至最后一次由word指定的字符之间的所有内容
    • 示例:
    file=“var/log/messages” ${file#*/}: log/messages ${file##*/}: messages
  3. ${var%word*}:其中word可以是指定的任意字符

    • 功能:自右而左,查找var变量所存储的字符串中,第一次出现的word, 删除字符串最后一个字符向左至第一次出现word字符串(含)之间的所有字符
    • 例子:
    file="/var/log/messages" ${file%/*}: /var/log
  4. ${var%%word*}

    • 同上,只不过删除字符串最右侧的字符向左至最后一次出现word字符之间的所有字符
    • 示例:
    url=http://www.baidu.com:80 ${url##*:} 80 ${url%%:*} http

6.3. 字符串查找替换

  1. ${var/pattern/substr}
    • 查找var所表示的字符串中,第一次被pattern所匹配到的字符串,以substr替换之
  2. ${var//pattern/substr}
    • 查找var所表示的字符串中,所有能被pattern所匹配到的字符串,以substr替换之
  3. ${var/#pattern/substr}
    • 查找var所表示的字符串中,行首被pattern所匹配到的字符串,以substr替换之
  4. ${var/%pattern/substr}
    • 查找var所表示的字符串中,行尾被pattern所匹配到的字符串,以substr替换之

6.4. 字符串查找并删除

  1. ${var/pattern}
    • 删除var表示的字符串中第一次被pattern匹配到的字符串,从左往右匹配
  2. ${var//pattern}
    • 删除var表示的字符串中所有被pattern匹配到的字符串,从左往右匹配
  3. ${var/#pattern}
    • 删除var表示的字符串中所有以pattern为行首匹配到的字符串
  4. ${var/%pattern}
    • 删除var所表示的字符串中所有以pattern为行尾所匹配到的字符串

6.5. 字符大小写转换

  1. ${var^^}
    • 把var中的所有小写字母转换为大写
  2. ${var,,}
    • 把var中的所有大写字母转换为小写

6.6. 变量赋值的其他形式

shell脚本进阶-数组插图

  • 注意里面的expr是一个字符串,不是一个变量。直接就是双引号引起来的字符串。
最后修改日期: 2021年7月7日

作者

留言

撰写回覆或留言

发布留言必须填写的电子邮件地址不会公开。