已复制
全屏展示
复制代码

bash数组与字典总结


· 4 min read

一. 数组

bash 里面也有数组和字典,数组分为索引数组和关联数组(关联数组也就是在其他语言里面的字典,数组和字典的操作方式基本一致)。

declare -p 可以查询变量的属性名称和值,下面创建了一个 names 数组,然后查看数组的值。

yzy@cs:~$ declare -a names=("a" "b" "c" "d")
yzy@cs:~$ declare -p names
declare -a names=([0]="a" [1]="b" [2]="c" [3]="d")

1.1 创建数组

# 创建空数组:两种方式
names=()
declare -a names=()


# 创建数组同时赋值:两种方式
names=("a" "b" "c")
declare -a names=("a" "b" "c" "d")


# 在末尾添加元素
names=("a")
names+=("beijing" "shanghai" "guangzhou")


# 多个数组合并为一个数组
ages=(19 20 99)
names=(beijing shanghai)
ages_names=(${ages[@]} ${names[@]})


# 引用变量
names=("a" "b" "c" "$USER")


# 指定路径加通配符
files=(*)
photos=(~/"My Photos"/*.jpg)


# 通过指定索引号定义数组
names2[0]="Bob"
names2[4]="Bob4"


# 指定索引号,索引号不连续的也叫稀疏数组
names=([0]="Bob" [1]="Peter" [20]="$USER" [21]="Big Bad John")


# 精确匹配: 搜索数组里面的元素,如果元素包含了 shang,则替换成 sang
names=(beijing shanghai shangtian)
new_names=(${names[@]/shang/sang})


# 模糊匹配: 搜索数组里面的元素,如果元素以 shang 开头,则替换成 guizhou
names=(beijing shanghai shangtian)
new_names=(${names[@]/shang*/guizhou})

1.2 访问数组

# 数组下标访问
yzy@cs:~$ char=(a b c q w x y z)
yzy@cs:~$ echo "${char[2]}"
c


# 分片访问
# 表示从下标为 3 的位置开始访问 2 个元素
yzy@cs:~$ arr=(able good fly python java test go now)
yzy@cs:~$ echo "${arr[@]:3:2}"
python java


# 元素个数
yzy@cs:~$ arr=(a b c)
yzy@cs:~$ echo ${#arr[@]}
3


# 元素个数
yzy@cs:~$ myfiles=([0]=".bashrc" [1]="codes.xlsx" [4]="hello.c")
yzy@cs:~$ echo ${#myfiles[@]}
3


# 指定下标的元素值的字符个数
yzy@cs:~$ arr=(able good fly python java test go now)
yzy@cs:~$ echo "${#arr[3]}"
6

1.3 遍历数组

# 打印出变量的类型和值
yzy@cs:~$ myfiles=(/*)
yzy@cs:~$ declare -p myfiles


# 打印值
yzy@cs:~$ names=("Bob" "Peter" "$USER" "BigJohn")
yzy@cs:~$ printf '%s\n' "${names[@]}"
Bob
Peter
yzy
BigJohn


# 打印值
yzy@cs:~$ names=("Bob" "Peter" "$USER" "BigJohn")
yzy@cs:~$ echo "users: ${names[*]}"
users: Bob Peter yzy BigJohn


# 拷贝多个文件
myfiles=(db.sql home.bz2 etc.bz2)
cp "${myfiles[@]}" /backups/


# for 循环:获取元素
for file in "${myfiles[@]}"; do
    echo "$file"
done


# for 循环:获取索引
for i in "${!myfiles[@]}"; do
    echo "$i -> ${myfiles[i]}"
done


# 遍历数组下标,但是步长为2
mychars=(a b c q w x y z)
for ((i=0; i<${#mychars[@]}; i+=2)); do
    echo "${mychars[i]} and ${mychars[i+1]}"
done
# 结果
a and b
c and q
w and x
y and z

1.4 删除元素

删除指定下标的元素

yzy@cs:~$ mychars=(a b c q w)
yzy@cs:~$ declare -p mychars
declare -a mychars=([0]="a" [1]="b" [2]="c" [3]="q" [4]="w")

yzy@cs:~$ unset mychars[2]
yzy@cs:~$ declare -p mychars
declare -a mychars=([0]="a" [1]="b" [3]="q" [4]="w")

二. 字典

bash里面的字典叫做关联数组,字典其实和数组类似,不同点在于,字典的key是字符串,并且遍历时是随机的。

注意事项:

  • 字典的key遍历是随机的顺序, 它不适合存放顺序的元素
  • 除了遍历是随机的外, 字典的用法基本和数组是一致的

2.1 创建字典

一定要显示定义

# 方法1
yzy@cs:~$ declare -A ages
yzy@cs:~$ ages=(["wang"]=21 ["zhang"]=18)
yzy@cs:~$ echo "my age is ${ages[wang]}"
my age is 21


# 方法2
yzy@cs:~$ declare -A names
yzy@cs:~$ names["wang"]="wang xiao"
yzy@cs:~$ names["zhang"]="zhang xiao"
yzy@cs:~$ declare -p names
declare -A names=([zhang]="zhang xiao" [wang]="wang xiao" )

2.2 遍历字典

像遍历数组一样,只不过 index 变成字符串了

declare -A ages
ages=(["wang"]=21 ["zhang"]=18)
for name in "${!ages[@]}"; do
    echo "name: $name, age: ${ages[$name]}."
done
# 结果
name: zhang, age: 18.
name: wang, age: 21.

三. 总结

一句话总结:

  • for value in "${myfiles[@]}" 表示遍历数组的元素值
  • for index in "${!myfiles[@]}" 表示遍历数组的下标号
  • echo "${#myfiles[@]}" 表示获取数组的元素个数
  • echo "${names[*]}"  表示一次性的打印成字符串便于阅读
  • declare -a variable 表示定义一个数组
  • declare -A variable 表示定义一个字典
  • declare -p variable 表示打印遍历variable的类型、值

文章推荐