数组是一种常见的数据结构。跟大多数编程语言一样,大多数Linux shell脚本支持数组,但对数组的支持程度各不相同,比如数组的维度,是支持一维数组还是多维数组?再如,数组元素的下标是从 0 开始还是从1开始?则因shell而异,下面我们以zsh、sh、bash为例来讲解。
在Linux shell脚本编程中,定义数组有两种方法。
数值之间用空格间隔。
实例:
# csdn @ edu in ~ [21:37:32]
$ a=(1 'a' b)# csdn @ edu in ~ [21:37:42]
$ echo $a
1 a b
我们首先用命令 a=(1 'a' b) 定义了数组a
然后用命令 echo $a 显示数组a 的元素。
# csdn @ edu in ~ [22:20:47] C:1
$ echo 'a=(1 'a' b)' > a.sh# csdn @ edu in ~ [22:21:31]
$ echo 'echo $a' >> a.sh# csdn @ edu in ~ [22:21:48]
$ cat a.sh
a=(1 a b)
echo $a# csdn @ edu in ~ [22:21:51]
$ source ./a.sh
1 a b# csdn @ edu in ~ [22:22:01]
$
在上面的实例中,我们首先使用使用echo + 输出重定向方式将数组定义语句 echo 'a=(1 'a' b)' > a.sh 写入脚本文件 a.sh
然后 将 显示数组a元素的命令 echo 'echo $a' >> a.sh 写入脚本文件 a.sh
接下来我们使用cat命令查看脚本文件 a.sh的内容:
a=(1 a b)
echo $a
最后,我们使用命令 source ./a.sh 执行脚本文件a.sh。
注意,在上面创建的脚本文件 a.sh中,我们没有在第一行写入shebang或hashbang语句来指定脚本解释器。
[csdn ~]$ exec sh
sh-4.2$ a=(1 'a' b)
sh-4.2$ echo $a
1
sh-4.2$
sh-4.2$ echo 'a=(1 'a' b)' > a.sh
sh-4.2$ echo 'echo $a' >> a.sh
sh-4.2$ cat a.sh
a=(1 a b)
echo $a
sh-4.2$ . a.sh
sh: .: a.sh: file not found
sh-4.2$ source ./a.sh
1
sh-4.2$
# csdn @ edu in ~ [23:27:45] C:127
$ exec bash
[csdn ~]$ echo $0
bash
[csdn ~]$ a=(1 'a' b)
[csdn ~]$ echo $a
1
[csdn ~]$
在bash中,数组同样创建起来了,与上面不同的是,命令 echo $a 只显示了数组中的第1个元素,而不是所有元素。
[csdn ~]$ echo 'a=(1 'a' b)' > a.sh
[csdn ~]$ echo 'echo $a' >> a.sh
[csdn ~]$ cat a.sh
a=(1 a b)
echo $a
[csdn ~]$ . a.sh
1
[csdn ~]$
与上面的在命令行定义数组一样,bash中的命令 echo $a 只显示了数组中的第1个元素,而不是所有元素。
csdn @edu in ~ b[0]=0
zsh: b: assignment to invalid subscript range
csdn @edu in ~ b[1]=1
csdn @edu in ~ b[2]=a
csdn @edu in ~ echo $b
1 a
csdn @edu in ~
在上面的例子中,我们首先尝试直接在命令行定义数组元素:b[0]=0,但是zsh提示下标超出范围。
接下来,我们的命令 b[1]=1 和 b[2]=a 顺利完成,最后我们用命令 echo $b 显示 数组b的2个元素值:1 a。
可见,在zsh中,数组元素的下标是从1开始的。
$ echo 'b[0]=0' > b.sh
# csdn @ edu in ~ [22:07:01]
$ echo 'b[1]=1' >> b.sh# csdn @ edu in ~ [22:07:24]
$ echo 'b[2]=a' >> b.sh# csdn @ edu in ~ [22:07:39]
$ echo 'echo $b' >> b.sh# csdn @ edu in ~ [22:08:05]
$ cat b.sh
b[0]=0
b[1]=1
b[2]=a
echo $b# csdn @ edu in ~ [22:08:17]
$ source ./b.sh
./b.sh:1: b: assignment to invalid subscript range# csdn @ edu in ~ [22:08:27] C:126
$ bash ./b.sh
0# csdn @ edu in ~ [22:08:53]
$
接着我们使用echo + 输出重定向方式将数组定义语句
b[0]=0
b[1]=1
b[2]=a
写入脚本文件b.sh
然后 我们将 显示数组元素 的命令 echo 'echo $b' >> b.sh 写入脚本文件b.sh
随后我们使用命令 cat b.sh 查看脚本文件b.sh 的内容:
b[0]=0
b[1]=1
b[2]=a
echo $b
接下来我们使用命令 source ./b.sh 来执行脚本文件b.sh,但是命令在zsh下出错了:
./b.sh:1: b: assignment to invalid subscript range
这再次说明,在zsh中,数组元素的下标是从1开始的。
最后我们使用命令 bash ./b.sh 来执行脚本,命令顺利完成。
可见,在bash 中,数组元素的下标是从0开始的。
csdn @edu in ~ exec sh
sh-4.2$ b[0]=0
sh-4.2$ b[1]=1
sh-4.2$ b[2]=a
sh-4.2$ echo $b
0
sh-4.2$
数组成功创建,但只看到了数组中的第1个元素值。
sh-4.2$ echo 'b[0]=0' > b.sh
sh-4.2$ echo 'b[1]=1' >> b.sh
sh-4.2$ echo 'b[2]=a' >> b.sh
sh-4.2$ echo 'echo $b' >> b.sh
sh-4.2$ cat b.sh
b[0]=0
b[1]=1
echo $b
sh-4.2$ source ./b.sh
0
sh-4.2$
我们先使用echo + 输出重定向方式将数组定义语句
b[0]=0
b[1]=1
b[2]=a
写入脚本文件b.sh
然后 我们将 显示数组元素 的命令 echo 'echo $b' >> b.sh 写入脚本文件b.sh
随后我们使用命令 cat b.sh 查看脚本文件b.sh 的内容:
b[0]=0
b[1]=1
b[2]=a
echo $b
最后我们使用 source ./b. sh 命令来执行脚本文件b.sh,数组成功创建,但只看到了数组中的第1个元素值。
# csdn @ edu in ~ [23:53:42]
$ exec bash
[csdn ~]$ echo $0
bash
[csdn ~]$ b[0]=0
[csdn ~]$ b[1]=1
[csdn ~]$ b[2]=a
[csdn ~]$ echo $b
0
[csdn ~]$
命令全部顺利执行,可见在bash中,数组元素的下标是从0开始的,但echo $b只显示了数组第1个元素值。
[csdn ~]$ echo b[0]=0 > b.sh
[csdn ~]$ echo b[1]=1 >> b.sh
[csdn ~]$ echo b[2]=a >> b.sh
[csdn ~]$ echo 'echo $b' >> b.sh
[csdn ~]$ cat b.sh
b[0]=0
b[1]=1
b[2]=a
echo $b
[csdn ~]$ . b.sh
0
[csdn ~]$
在脚本文件中执行跟 命令行执行结果是一样的。
在zsh中,数组元素的下标是从 1 开始的,使用“$数组名” 可以获得数组所有元素值。
在sh和bash中,数组元素的下标是从 0 开始的,使用“$数组名” 只能获得数组第1个元素值。
通过上面的实例,我们发现在sh和bash中,使用“$数组名” 只能获得数组第1个元素值,那么如何获取所有的数组元素呢?我们可以使用* 或 @ 作为下标来获取,具体格式即:
${数组名[@]}
或
${数组名[*]}
# csdn @ edu in ~ [12:24:50]
$ echo $0
/bin/zsh# csdn @ edu in ~ [12:25:24]
$ a=(1 2 'a')# csdn @ edu in ~ [12:25:42]
$ echo $a
1 2 a# csdn @ edu in ~ [12:27:06]
$ echo ${a[@]}
1 2 a# csdn @ edu in ~ [12:27:39]
$ echo ${a[*]}
1 2 a# csdn @ edu in ~ [12:32:40]
$
# csdn @ edu in ~ [12:32:40]
$ exec sh
sh-4.2$ a=(1 2 'a')
sh-4.2$ echo $a
1
sh-4.2$ echo ${a[@]}
1 2 a
sh-4.2$ echo ${a[*]}
1 2 a
sh-4.2$
sh-4.2$ exec bash
[csdn ~]$ a=(1 2 'a')
[csdn ~]$ echo $a
1
[csdn ~]$ echo ${a[@]}
1 2 a
[csdn ~]$ echo ${a[*]}
1 2 a
[csdn ~]$
在介绍字符串时,我们说过获取字符串的格式是:${#字符串名},获取数组或数组元素长度的格式是相似的:
${#数组名[下标]}
或
${#数组名[下标]}
如果要取数组的长度,那么下标就用*或 @。如果要取数组某个元素的长度,那么下标就用元素的下标。
# csdn @ edu in ~ [12:57:21]
$ echo $0
/bin/zsh# csdn @ edu in ~ [12:57:24]
$ b[1]=1# csdn @ edu in ~ [12:57:31]
$ b[2]=22# csdn @ edu in ~ [12:57:36]
$ echo ${b[*]}
1 22# csdn @ edu in ~ [12:57:49]
$ echo ${#b[*]}
2# csdn @ edu in ~ [12:57:55]
$ echo ${#b[@]}
2# csdn @ edu in ~ [12:57:59]
$ echo ${b[0]}
# csdn @ edu in ~ [12:58:07]
$ echo ${#b[0]}
0# csdn @ edu in ~ [12:58:11]
$ echo ${b[1]}
1# csdn @ edu in ~ [12:58:26]
$ echo ${#b[1]}
1# csdn @ edu in ~ [12:58:30]
$ echo ${b[2]}
22# csdn @ edu in ~ [12:58:35]
$ echo ${#b[2]}
2
# csdn @ edu in ~ [13:07:28]
$ exec sh
sh-4.2$ b[1]=1
sh-4.2$ b[2]=22
sh-4.2$ echo ${b[*]}
1 22
sh-4.2$ echo ${#b[*]}
2
sh-4.2$ echo ${#b[@]}
2
sh-4.2$ echo ${b[0]}sh-4.2$ echo ${#b[0]}
0
sh-4.2$ echo ${b[1]}
1
sh-4.2$ echo ${#b[1]}
1
sh-4.2$ echo ${b[2]}
22
sh-4.2$ echo ${#b[2]}
2
sh-4.2$
[csdn ~]$ b[1]=1
[csdn ~]$ b[2]=22
[csdn ~]$ echo ${b[@]}
1 22
[csdn ~]$ echo ${#b[@]}
2
[csdn ~]$ echo ${#b[*]}
2
[csdn ~]$ echo ${b[0]}[csdn ~]$ echo ${#b[0]}
0
[csdn ~]$ echo ${b[1]}
1
[csdn ~]$ echo ${#b[1]}
1
[csdn ~]$ echo ${b[2]}
22
[csdn ~]$ echo ${#b[2]}
2
[csdn ~]$
在上面的实例中,由于zsh中数组元素下标是从1开始的,所以我们定义数组b时,是从下标为1 的元素开始的。
然后我们先获取整个数组的元素值和长度,然后从下标0开始获取数组每个元素的值和长度。
值得注意的是,我们使用命令 echo ${b[0]} 尝试显示数组b中下标为0 的元素值 时,系统没有提示出错;使用命令echo ${#b[0]}尝试显示数组b中下标为0 的元素的长度时,系统反馈为0。