【Linux入门】shell基础篇——数组

数组

在 Bash 中,数组是一种非常有用的数据结构,可以存储多个值

数组定义方法

  1. 方法一:直接赋值
arr=(value0 value1 value2 ...)

例如:

arr=(1 2 3 4 5)
  1. 方法二:使用索引赋值
arr=([0]=value [1]=value [2]=value ...)

例如:

arr=([0]=1 [1]=2 [2]=3)
  1. 方法三:从字符串创建数组
list="value0 value1 value2 ..."
arr=($list)

例如:

list="1 2 3 4"
arr2=($list)
  1. 方法四:逐个赋值
arr[0]="value"
arr[1]="value"
arr[2]="value"

例如:

arr3[0]="1"
arr3[1]="2"
arr3[2]="3"

数组展开

  • "$*":将所有参数作为一个整体展开。
  • "$@":将每个参数分别展开。
  • "$#":返回参数的数量。

示例

#!/bin/bash

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

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

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

注意:

  • for 循环中,建议使用双引号来避免潜在的单词分割问题。
  • ${arr[*]}${arr[@]} 的区别在于,${arr[*]} 将数组元素作为一个整体字符串展开,而 ${arr[@]} 将每个元素分别展开为独立的字符串。

数组包括的数据类型

  • 数值类型:整数、浮点数等。
  • 字符类型:使用单引号 ' ' 或双引号 " " 定义的字符串。

获取数组长度

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

[root@loaclhost shuzu1]# arr1=(1 2 3 4 5)
[root@loaclhost shuzu1]# echo ${#arr1[*]} # 也就是数组中总共多少个元素
5

读取某下标赋值

使用 ${arr[index]} 可以读取指定下标的数组元素,并进行赋值。
示例:

[root@loaclhost shuzu1]# arr1=(1 2 3 4 5)
[root@lo.amazonaws.com shuzu1]# echo ${arr1[0]} # 获取索引为0的元素,即第一个元素
1
[root@loaclhost shuzu1]# echo ${arr1[3]} # 获取索引为3的元素,即第四个元素
4

数组遍历

可以使用 for 循环遍历数组中的所有元素。
示例脚本 a.sh

#!/bin/bash
arr5=(1 2 3 4 5)
for i in "${arr5[@]}"; do
    echo $i
done

运行脚本:

[root@loaclhost shuzu1]# chmod +x a.sh
[root@loaclhost shuzu1]# ./a.sh # 将数组中的元素列出来就叫数组遍历
1
2
3
4
5

注意:

  • for 循环中,建议使用双引号来避免潜在的单词分割问题。
  • ${arr[*]}${arr[@]} 的区别在于,${arr[*]} 将数组元素作为一个整体字符串展开,而 ${arr[@]} 将每个元素分别展开为独立的字符串。

数组切片

数组切片允许你获取数组中的某一段元素的值。

  • 格式:${数组名[@或*]}:起始位置(起始索引):长度
  • 示例:
[root@loaclhost shuzu1]# arr1=(1 2 3 4 5)
[root@loaclhost shuzu1]# echo ${arr1[*]} # 输出整个数组
1 2 3 4 5
[root@loaclhost shuzu1]# echo ${arr1[*]:0:2} # 从索引0开始获取往后两位元素的值
1 2
[root@loaclhost shuzu1]# echo ${arr1[*]:2:2} # 从索引2开始获取往后两位元素的值
3 4

数组替换

数组替换允许你临时或永久地替换数组中的元素。

  • 临时替换格式:${数组名[@或*]/查找字符/替换字符}
  • 永久替换方法:通过重新赋值实现。
  • 示例:
[root@loaclhost shuzu1]# arr1=(1 2 3 4 5)
[root@loaclhost shuzu1]# echo ${arr1[*]/4/66} # 将数组中的元素4临时替换为66
1 2 3 66 5
[root@loaclhost shuzu1]# echo ${arr1[*]} # 原来的数组元素值不变
1 2 3 4 5
[root@loaclhost shuzu1]# arr1=(${arr1[*]/4/66}) # 永久替换
[root@loaclhost shuzu1]# echo ${arr1[*]} # 替换后的数组
1 2 3 66 5

删除数组

使用 unset 命令可以删除整个数组或数组中的某个元素。

  • 删除整个数组:unset arr1
  • 删除数组中的某个元素:unset arr1[索引]
  • 示例:
[root@loaclhost shuzu1]# unset arr1
[root@loaclhost shuzu1]# echo ${arr1[*]} # 数组已被删除
[root@loaclhost shuzu1]# arr1=(1 2 3 4 5)
[root@loaclhost shuzu1]# echo ${arr1[*]} # 输出整个数组
1 2 3 4 5
[root@loaclhost shuzu1]# unset arr1[2] # 删除索引2对应的元素
[root@loaclhost shuzu1]# echo ${arr1[*]} # 删除后的数组
1 2 4 5

追加数组中的元素

方法一:直接指定索引

当你知道要追加的位置时,可以直接指定索引并赋值。如果索引超出了当前数组的范围,Bash 会自动扩展数组。

arr1=(1 2 3 4 5)
arr1[5]=6  # 追加索引为5的元素
echo ${arr1[*]}  # 输出 1 2 3 4 5 6

方法二:使用数组长度

如果要在数组末尾追加元素,可以使用 ${#arr1[@]} 来获取数组长度,并将其作为新元素的索引。

arr1[${#arr1[@]}]=7  # 追加新元素到末尾
echo ${arr1[*]}  # 输出 1 2 3 4 5 7

方法三:使用 += 操作符

+= 操作符可以直接将新元素追加到数组末尾,这种方式更加直观和方便。

arr1=(1 2 3 4 5)
arr1+=(6 7)  # 追加多个元素
echo ${arr1[*]}  # 输出 1 2 3 4 5 6 7

注意,这里不需要将 ${arr1[@]} 放在双引号内,因为 += 操作符会自动处理。

方法四(补充):使用 readarraymapfile(Bash 4.0+)

如果你的 Bash 版本支持 readarray(或等价的 mapfile),你还可以从文件或其他命令的输出中直接读取到数组中。但这不是直接追加元素的方法,而是另一种填充数组的方式。

# 假设有一个文件 list.txt 包含一些要追加的元素
readarray -t arr1 < list.txt  # 注意,这会覆盖 arr1 的现有内容

好的,我会更详细地解释上述内容

向函数传数组参数

在 Bash 中,当你尝试将一个数组作为参数传递给函数时,函数只会接收到数组的第一个元素。这是因为 Bash 不支持将整个数组作为一个单独的参数传递。

问题展示

考虑以下脚本 b.sh

#!/bin/bash
test1 () {
  echo "接受到的参数列表:$@"
  abc2=$1
  echo "新数组的值为:${abc2[*]}"
}
abc=(3 2 1 4 5)
echo "原始数组的值为:${abc[*]}"
test1 $abc

执行此脚本时,你会看到:

原始数组的值为:3 2 1 4 5
接受到的参数列表:3
新数组的值为:3

如你所见,函数 test1 只接收到了数组 abc 的第一个元素。

2. 解决方案

为了解决这个问题,你可以:

  • 将数组的每个元素作为单独的参数传递给函数。
  • 在函数内部,使用 $@$*(加双引号)来接收这些参数,并重新组合它们为一个数组。
    考虑以下脚本 c.sh
#!/bin/bash
test2 () {
  abc1=($@)  # 使用 $@ 接收所有参数,并重新组合为数组
  echo "新数组的值为:${abc1[*]}"
}
abc=(seq 1 10)
test2 ${abc[*]}  # 将数组的值分解为单个的值并传递

执行此脚本时,你会看到:

新数组的值为:1 2 3 4 5 6 7 8 9 10

3. 从函数返回数组

你还可以从函数中返回一个数组。这通常涉及到在函数内部生成一个数组,并使用 echo 打印其元素,然后在函数外部捕获这些输出并重新组合为一个数组。
例如,考虑一个执行加法运算的函数:

#!/bin/bash
test2 () {
  abc1=($@)
  sum=0
  for i in ${abc1[*]}
  do
    sum=$((sum + i))
  done
  echo "$sum"
}
abc=(3 2 1 4 5)
result=$(test2 ${abc[*]})
echo "加法结果为:$result"

此脚本会输出:

加法结果为:15

另一个例子是乘法运算:

#!/bin/bash
test3 () {
  abc1=($@)
  for ((i=0; i<${#abc1[@]}; i++))
  do
    abc1[i]=$((abc1[i] * 2))
  done
  echo "${abc1[*]}"
}
abc=(1 2 3)
result=($(test3 ${abc[*]}))
echo "乘法结果为:${result[*]}"

此脚本会输出:

乘法结果为:2 4 6

数组排序算法:冒泡排序

冒泡排序的基本思想

冒泡排序的基本思想是:每次遍历数组时,比较相邻的两个元素,如果它们的顺序不正确(例如,对于升序排序,较大的元素在较小的元素前面),则交换它们的位置。这个过程会重复进行,直到整个数组排序完成。

冒泡排序的 Bash 实现

示例:

#!/bin/bash
bubble_sort() {
  local arr=("${!1}")
  local len=${#arr[@]}
  for ((i = 0; i < len; i++)); do
    for ((j = 0; j < len - i - 1; j++)); do
      if [[ ${arr[j]} -gt ${arr[j + 1]} ]]; then
        # 交换元素
        temp=${arr[j]}
        arr[j]=${arr[j + 1]}
        arr[j + 1]=$temp
      fi
    done
  done
  echo "${arr[@]}"
}

# 示例数组
numbers=(5 3 8 1 6)
echo "原始数组:${numbers[*]}"
sorted_numbers=($(bubble_sort numbers[@]))
echo "排序后的数组:${sorted_numbers[*]}"

解释

  1. 函数定义bubble_sort 函数接受一个数组引用作为参数。
  2. 数组解引用:使用 ${!1} 解引用传递的数组引用,获取实际的数组。
  3. 外层循环:外层循环控制排序的轮数,总共需要进行 len - 1 轮。
  4. 内层循环:内层循环用于比较相邻的元素,如果顺序不正确则交换它们。
  5. 交换元素:使用临时变量 temp 交换两个元素的值。
  6. 输出结果:排序完成后,输出排序后的数组。

运行示例

$ ./bubble_sort.sh
原始数组:5 3 8 1 6
排序后的数组:1 3 5 6 8

注意事项

  1. 数组引用:传递数组时使用 @ 而不是 *,因为 @ 会保留数组的每个元素作为单独的参数,而 * 会将所有元素作为一个字符串传递。
  2. 解引用:在函数内部使用 ${!1} 解引用传递的数组引用。
  3. 交换元素:使用临时变量 temp 进行元素交换。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值