数组不是 Shell 的强项,但用好了能简化很多逻辑。Bash 支持普通数组和关联数组,基本够用。
定义数组
# 方式一:括号定义
FRUITS=("apple" "banana" "orange")
# 方式二:逐个赋值
FRUITS[0]="apple"
FRUITS[1]="banana"
FRUITS[2]="orange"
# 方式三:declare 声明
declare -a FRUITS
FRUITS=("apple" "banana" "orange")
访问元素
FRUITS=("apple" "banana" "orange")
# 访问单个元素(索引从0开始)
echo ${FRUITS[0]} # apple
echo ${FRUITS[1]} # banana
# 访问所有元素
echo ${FRUITS[@]} # apple banana orange
echo ${FRUITS[*]} # apple banana orange
# 访问索引
echo ${!FRUITS[@]} # 0 1 2
# 数组长度
echo ${#FRUITS[@]} # 3
# 单个元素长度
echo ${#FRUITS[0]} # 5
添加元素
FRUITS=("apple" "banana")
# 追加元素
FRUITS+=("orange")
FRUITS+=("grape" "mango")
# 指定索引添加
FRUITS[5]="kiwi" # 索引可以不连续
echo ${FRUITS[@]} # apple banana orange grape mango kiwi
echo ${#FRUITS[@]} # 6
删除元素
FRUITS=("apple" "banana" "orange")
# 删除单个元素
unset FRUITS[1]
echo ${FRUITS[@]} # apple orange
# 删除整个数组
unset FRUITS
数组切片
FRUITS=("apple" "banana" "orange" "grape" "mango")
# 从索引1开始,取3个元素
echo ${FRUITS[@]:1:3} # banana orange grape
# 从索引2开始,取到最后
echo ${FRUITS[@]:2} # orange grape mango
遍历元素
FRUITS=("apple" "banana" "orange")
# 方式一
for FRUIT in ${FRUITS[@]}; do
echo $FRUIT
done
# 方式二(推荐,处理带空格的元素)
for FRUIT in "${FRUITS[@]}"; do
echo $FRUIT
done
# 方式三:带索引
for I in ${!FRUITS[@]}; do
echo "$I: ${FRUITS[$I]}"
done
C 风格遍历
FRUITS=("apple" "banana" "orange")
LEN=${#FRUITS[@]}
for ((I=0; I<LEN; I++)); do
echo "${FRUITS[$I]}"
done
关联数组就是键值对,类似其他语言的 Map 或字典。
定义关联数组
# 必须先声明
declare -A USER
USER[name]="张三"
USER[age]=25
USER[city]="北京"
# 或一次性定义
declare -A USER=(
[name]="张三"
[age]=25
[city]="北京"
)
访问和操作
# 访问元素
echo ${USER[name]} # 张三
# 所有值
echo ${USER[@]} # 张三 25 北京
# 所有键
echo ${!USER[@]} # name age city
# 元素个数
echo ${#USER[@]} # 3
# 判断键是否存在
if [[ -v USER[name] ]]; then
echo "name 存在"
fi
遍历关联数组
declare -A USER=(
[name]="张三"
[age]=25
[city]="北京"
)
# 遍历键
for KEY in ${!USER[@]}; do
echo "$KEY: ${USER[$KEY]}"
done
# 输出类似:
# name: 张三
# age: 25
# city: 北京
数组转字符串
FRUITS=("apple" "banana" "orange")
# 用空格连接
STR="${FRUITS[*]}"
echo $STR # apple banana orange
# 用指定分隔符连接
STR=$(IFS=','; echo "${FRUITS[*]}")
echo $STR # apple,banana,orange
字符串转数组
STR="apple,banana,orange"
# 用 IFS 分割
IFS=',' read -ra FRUITS <<< "$STR"
echo ${FRUITS[@]} # apple banana orange
数组去重
FRUITS=("apple" "banana" "apple" "orange" "banana")
# 用关联数组去重
declare -A SEEN
UNIQUE=()
for FRUIT in "${FRUITS[@]}"; do
if [[ -z ${SEEN[$FRUIT]} ]]; then
UNIQUE+=("$FRUIT")
SEEN[$FRUIT]=1
fi
done
echo ${UNIQUE[@]} # apple banana orange
数组包含判断
FRUITS=("apple" "banana" "orange")
# 判断元素是否存在
contains() {
local ELEMENT=$1
shift
local ARR=("$@")
for ITEM in "${ARR[@]}"; do
[[ $ITEM == $ELEMENT ]] && return 0
done
return 1
}
if contains "banana" "${FRUITS[@]}"; then
echo "包含 banana"
fi
数组合并
A=("a" "b")
B=("c" "d")
# 合并
C=("${A[@]}" "${B[@]}")
echo ${C[@]} # a b c d
数组使用要点:
() 定义declare -A${ARR[index]}${#ARR[@]}"${ARR[@]}"(加引号)