Shell 数组是处理多个数据的集合,支持一维数组(普通数组)和关联数组(键值对)。以下是 Shell 数组的详细讲解:
一、数组的定义
1. 普通数组
普通数组的索引从 0
开始,支持整数作为下标。
-
直接定义:
array=(value0 value1 value2)
示例:
fruits=("apple" "banana" "orange")
-
指定下标定义:
array=([0]="a" [2]="b" [5]="c")
输出:
a
(下标0)、空(下标1未定义)、b
(下标2)、空(下标3-4未定义)、c
(下标5)。 -
间接定义:
list="value1 value2 value3" array=($list)
2. 关联数组
关联数组支持字符串或整数作为键(下标),需先声明再使用。
-
声明与定义:
关联数组使用
declare
命令来声明declare -A info info=([name]="Alice" [age]=25 [city]="Shanghai")
二、数组的访问
1. 访问单个元素
-
普通数组:
echo ${array[0]} # 访问第一个元素
-
关联数组:
echo ${info[name]} # 访问键为"name"的值
2. 访问所有元素
-
使用
@
或*
:echo ${array[@]} # 所有元素,用空格分隔 echo ${array[*]} # 效果同上
注意:后面会讲解一下区别
3. 获取数组长度
-
元素个数:
length=${#array[@]} # 或 ${#array[*]}
-
单个元素长度:
length_of_element=${#array[0]} # 获取第一个元素的字符数
4. 获取所有下标
在数组前加一个感叹号 ! 可以获取数组的所有键
echo ${!array[@]} # 输出所有下标(如:0 1 2)
echo ${!array[*]} # 输出所有下标(如:0 1 2)
三、数组的操作
1. 添加元素
-
追加到末尾:
array+=("new_element")
-
指定下标添加:
array[3]="d"
2. 修改元素
array[1]="updated_value"
3. 删除元素
-
删除单个元素:
unset array[1] # 删除下标为1的元素,数组下标不会重新排序
-
删除整个数组:
unset array
4. 数组切片
-
语法:
${array[@]:起始位置:长度}
echo ${array[@]:1:2} # 从下标1开始,取2个元素
5. 数组拼接
array1=(1 2 3)
array2=(4 5 6)
combined=("${array1[@]}" "${array2[@]}")
6. 数组替换
array=(${array[@]/old_value/new_value}) # 替换所有匹配项
四、数组的遍历
1. 普通遍历
for item in "${array[@]}"; do
echo "$item"
done
注意:使用双引号包裹 ${array[@]}
,避免元素中包含空格时被错误分割。
2. 带索引的遍历
for i in "${!array[@]}"; do
echo "Index $i: ${array[$i]}"
done
五、关联数组的特殊操作
-
声明关联数组:
declare -A map
-
赋值:
map[key1]="value1"
-
遍历键和值:
for key in "${!map[@]}"; do echo "Key: $key, Value: ${map[$key]}" done
六、常见注意事项
-
下标从0开始:普通数组的下标必须为非负整数。
-
空格分隔元素:数组元素之间用空格分隔,逗号会被当作一个整体。
array=(1,2,3) # 错误:会被当作一个元素(值为"1,2,3") array=(1 2 3) # 正确
-
元素可为空:未定义的下标访问时会返回空。
-
unset后索引不重排:删除元素后,其他元素的下标不会改变。
array=(a b c) unset array[1] echo ${array[@]} # 输出 a c echo ${!array[@]} # 输出 0 2
七、@
和 *
区别💥
在 Shell 数组中,@
和 *
都可以用来获取数组的所有元素,但它们的行为在是否被双引号包裹的情况下有显著区别。以下是详细对比:
1. 未被双引号包裹时(无引号)
-
@
和*
的行为相同:
两者都会将数组的每个元素视为独立的字符串,彼此之间用空格分隔。 -
示例:
arr=(a b c) echo ${arr[@]} # 输出: a b c echo ${arr[*]} # 输出: a b c
2. 被双引号包裹时(有引号)
@
和*
的行为不同:${array[@]}
:
将数组的每个元素视为独立的字符串,并保留每个元素的原始内容(包括空格)。
在循环中,每个元素会被单独处理。${array[*]}
:
将数组的所有元素合并为一个字符串(默认用空格分隔),并作为一个整体处理。
在循环中,整个字符串会被视为单个元素。
示例 1:普通元素
arr=(a b c)
# 使用 ${array[@]}
for i in "${arr[@]}"; do
echo "$i"
done
# 输出:
# a
# b
# c
# 使用 ${array[*]}
for i in "${arr[*]}"; do
echo "$i"
done
# 输出:
# a b c
示例 2:元素包含空格
arr=("hello world" "good morning")
# 使用 ${array[@]}
for i in "${arr[@]}"; do
echo "$i"
done
# 输出:
# hello world
# good morning
# 使用 ${array[*]}
for i in "${arr[*]}"; do
echo "$i"
done
# 输出:
# hello world good morning
3. 关键区别总结
场景 | ${array[@]} | ${array[*]} |
---|---|---|
未被双引号包裹 | 每个元素独立,用空格分隔 | 每个元素独立,用空格分隔 |
被双引号包裹 | 每个元素独立,保留空格等原始内容 | 所有元素合并为一个字符串(默认空格分隔) |
适用场景 | 遍历数组、处理带空格的元素 | 合并所有元素为一个整体 |
4. 推荐用法
-
遍历数组时:
始终使用${array[@]}
,因为它能正确处理带空格的元素。for item in "${arr[@]}"; do echo "$item" done
-
合并所有元素为一个字符串时:
使用${array[*]}
,但需注意默认分隔符是空格(可通过IFS
修改)。IFS=',' # 修改分隔符为逗号 joined="${arr[*]}" echo "$joined" # 输出: a,b,c
5. 特殊变量的类比
@
和 *
的区别也适用于 Shell 的特殊变量(如 $@
和 $*
):
$@
:表示所有脚本参数(或函数参数),每个参数独立。$*
:表示所有参数合并为一个字符串(默认空格分隔)。
例如:
# 脚本 test.sh
for arg in "$*"; do
echo "arg: $arg"
done
# 执行脚本
./test.sh a b c
# 输出:
# arg: a b c
总结
@
:始终将数组(或参数)的每个元素视为独立个体。*
:将数组(或参数)合并为一个整体(默认空格分隔)。
在需要保留元素独立性(尤其是处理带空格的字符串)时,优先使用${array[@]}
。
八、示例代码
#!/bin/bash
# 定义普通数组
fruits=("apple" "banana" "orange")
# 添加元素
fruits+=("grape")
# 修改元素
fruits[1]="blueberry"
# 获取长度
echo "Length: ${#fruits[@]}"
# 访问所有元素
echo "All elements: ${fruits[@]}"
# 访问单个元素
echo "Third element: ${fruits[2]}"
# 数组切片
echo "Slice: ${fruits[@]:1:2}"
# 删除元素
unset fruits[1]
# 遍历数组
for fruit in "${fruits[@]}"; do
echo "Fruit: $fruit"
done
# 定义关联数组
declare -A person
person[name]="Alice"
person[age]=30
# 遍历关联数组
for key in "${!person[@]}"; do
echo "$key: ${person[$key]}"
done
九、总结
- Shell 数组支持普通数组和关联数组,适用于存储和操作一组数据。
- 掌握数组的定义、访问、修改、遍历和高级操作(如切片、拼接)是编写高效 Shell 脚本的关键。
- 注意空格分隔、下标索引和 unset 操作的影响,避免常见错误。
👍 自由不是随心所欲,而是自我掌控的能力
😊 **希望对你有帮助!