数组

    数组可以采用逐个赋值的方法创建。

    上面语法中,是数组的名字,可以是任意合法的变量名。INDEX是一个大于或等于零的整数,也可以是算术表达式。注意数组第一个元素的下标是0, 而不是1。

    下面创建一个三个成员的数组。

    1. $ array[0]=val
    2. $ array[1]=val
    3. $ array[2]=val

    数组也可以采用一次性赋值的方式创建。

    1. ARRAY=(value1 value2 ... valueN)
    2. # 等同于
    3. ARRAY=(
    4. value1
    5. value2
    6. value3
    7. )

    采用上面方式创建数组时,可以按照默认顺序赋值,也可以在每个值前面指定位置。

    1. $ array=(a b c)
    2. $ array=([2]=c [0]=a [1]=b)
    3. $ days=(Sun Mon Tue Wed Thu Fri Sat)
    4. $ days=([0]=Sun [1]=Mon [2]=Tue [3]=Wed [4]=Thu [5]=Fri [6]=Sat)

    只为某些值指定位置,也是可以的。

    1. names=(hatter [5]=duchess alice)

    上面例子中,hatter是数组的0号位置,duchess是5号位置,alice是6号位置。

    没有赋值的数组元素的默认值是空字符串。

    定义数组的时候,可以使用通配符。

    1. $ mp3s=( *.mp3 )

    上面例子中,将当前目录的所有 MP3 文件,放进一个数组。

    先用declare -a命令声明一个数组,也是可以的。

    1. $ declare -a ARRAYNAME

    read -a命令则是将用户的命令行输入,读入一个数组。

    1. $ read -a dice

    上面命令将用户的命令行输入,读入数组dice

    读取数组

    读取数组指定位置的成员,要使用下面的语法。

    1. $ echo ${array[i]} # i 是索引

    上面语法里面的大括号是必不可少的,否则 Bash 会把索引部分[i]按照原样输出。

    1. $ array[0]=a
    2. $ echo ${array[0]}
    3. a
    4. $ echo $array[0]
    5. a[0]

    上面例子中,数组的第一个元素是a。如果不加大括号,Bash 会直接读取$array首成员的值,然后将[0]按照原样输出。

    @*是数组的特殊索引,表示返回数组的所有成员。

    1. $ foo=(a b c d e f)
    2. $ echo ${foo[@]}
    3. a b c d e f

    这两个特殊索引配合for循环,就可以用来遍历数组。

    1. $ activities=( swimming "water skiing" canoeing "white-water rafting" surfing )
    2. $ for act in ${activities[@]}; \
    3. do \
    4. echo "Activity: $act"; \
    5. done
    6. Activity: water
    7. Activity: skiing
    8. Activity: canoeing
    9. Activity: white-water
    10. Activity: rafting
    11. Activity: surfing

    上面的例子中,数组activities实际包含5个元素,但是循环直接遍历${activities[@]},会导致返回7个结果。为了避免这种情况,一般把${activities[@]}放在双引号之中。

    1. $ for act in "${activities[@]}"; \
    2. do \
    3. echo "Activity: $act"; \
    4. done
    5. Activity: swimming
    6. Activity: water skiing
    7. Activity: canoeing
    8. Activity: white-water rafting
    9. Activity: surfing

    上面例子中,${activities[@]}放在双引号之中,遍历就会返回正确的结果。

    ${activities[*]}不放在双引号之中,跟${activities[@]}不放在双引号之中是一样的。

    1. $ for act in ${activities[*]}; \
    2. do \
    3. echo "Activity: $act"; \
    4. done
    5. Activity: swimming
    6. Activity: water
    7. Activity: skiing
    8. Activity: canoeing
    9. Activity: white-water
    10. Activity: rafting
    11. Activity: surfing

    ${activities[*]}放在双引号之中,所有元素就会变成单个字符串返回。

    1. $ for act in "${activities[*]}"; \
    2. do \
    3. echo "Activity: $act"; \
    4. done
    5. Activity: swimming water skiing canoeing white-water rafting surfing

    所以,拷贝一个数组的最方便方法,就是写成下面这样。

    1. $ hobbies=( "${activities[@]}" )

    上面例子中,数组activities被拷贝给了另一个数组hobbies

    这种写法也可以用来为新数组添加成员。

    1. $ hobbies=( "${activities[@]" diving )

    上面例子中,新数组hobbies在数组activities的所有成员之后,又添加了一个成员。

    如果读取数组成员时,没有读取指定哪一个位置的成员,默认使用0号位置。

    1. $ declare -a foo
    2. $ foo=A
    3. $ echo ${foo[0]}
    4. A

    上面例子中,foo是一个数组,赋值的时候不指定位置,实际上是给foo[0]赋值。

    引用一个不带下标的数组变量,则引用的是0号位置的数组元素。

    1. $ foo=(a b c d e f)
    2. $ echo ${foo}
    3. a
    4. $ echo $foo
    5. a

    上面例子中,引用数组元素的时候,没有指定位置,结果返回的是0号位置。

    要想知道数组的长度(即一共包含多少成员),可以使用下面两种语法。

    1. ${#array[*]}
    2. ${#array[@]}

    下面是一个例子。

    1. $ a[100]=foo
    2. 1
    3. $ echo ${#a[@]}

    上面例子中,把字符串赋值给100位置的数组元素,这时的数组只有一个元素。

    注意,如果用这种语法去读取具体的数组成员,就会返回该成员的字符串长度。这一点必须小心。

    上面例子中,${#a[100]}实际上是返回数组第100号成员a[100]的值(foo)的字符串长度。

    提取数组序号

    ${!array[@]}${!array[*]},可以返回数组的成员序号,即哪些位置是有值的。

    1. $ arr=([5]=a [9]=b [23]=c)
    2. $ echo ${!arr[@]}
    3. 5 9 23
    4. $ echo ${!arr[*]}
    5. 5 9 23

    利用这个语法,也可以通过for循环遍历数组。

    1. arr=(a b c d)
    2. for i in ${!arr[@]};do
    3. echo ${arr[i]}
    4. done

    ${array[@]:position:length}的语法可以提取数组成员。

    1. $ food=( apples bananas cucumbers dates eggs fajitas grapes )
    2. $ echo ${food[@]:1:1}
    3. bananas
    4. $ echo ${food[@]:1:3}
    5. bananas cucumbers dates

    上面例子中,${food[@]:1:1}返回从数组1号位置开始的1个成员,${food[@]:1:3}返回从1号位置开始的3个成员。

    如果省略长度参数length,则返回从指定位置开始的所有成员。

    1. $ echo ${food[@]:4}
    2. eggs fajitas grapes

    上面例子返回从4号位置开始到结束的所有成员。

    追加数组成员

    数组末尾追加成员,可以使用+=赋值运算符。它能够自动地把值追加到数组末尾。否则,就需要知道数组的最大序号,比较麻烦。

    1. $ foo=(a b c)
    2. $ echo ${foo[@]}
    3. a b c
    4. $ foo+=(d e f)
    5. $ echo ${foo[@]}
    6. a b c d e f

    删除一个数组成员,使用unset命令。

    1. $ foo=(a b c d e f)
    2. $ echo ${foo[@]}
    3. a b c d e f
    4. $ unset foo[2]
    5. $ echo ${foo[@]}
    6. a b d e f

    上面例子中,删除了数组中的第三个元素,下标为2。

    删除成员也可以将这个成员设为空值。

    1. $ foo=(a b c d e f)
    2. $ foo[1]=''
    3. $ echo ${foo[@]}
    4. a c d e f

    上面例子中,将数组的第二个成员设为空字符串,就删除了这个成员。

    由于空值就是空字符串,所以下面这样写也可以,但是不建议这种写法。

    1. $ foo[1]=

    上面的写法也相当于删除了数组的第二个成员。

    直接将数组变量赋值为空字符串,相当于删除数组的第一个成员。

    1. $ foo=(a b c d e f)
    2. $ foo=''
    3. $ echo ${foo[@]}
    4. b c d e f

    上面的写法相当于删除了数组的第一个成员。

    unset ArrayName可以清空整个数组。

    1. $ unset ARRAY
    2. $ echo ${ARRAY[*]}
    3. <--no output-->

    关联数组

    Bash 的新版本支持关联数组。关联数组使用字符串而不是整数作为数组索引。

    declare -A可以声明关联数组。

    整数索引的数组,可以直接使用变量名创建数组,关联数组则必须用带有-A选项的declare命令声明创建。

    1. echo ${colors["blue"]}