一、 Linux shell 脚本编程中的数组概述
数组是一种常见的数据结构。跟大多数编程语言一样,大多数Linux shell脚本支持数组,但对数组的支持程度各不相同,比如数组的维度,是支持一维数组还是多维数组?再如,数组元素的下标是从 0 开始还是从1开始?则因shell而异,下面我们以zsh、sh、bash为例来讲解。
二、数组的定义
在Linux shell脚本编程中,定义数组有两种方法。
(一)数组名=(数值1 数值2 ...... 数值n)
数值之间用空格间隔。
实例:
1.在zsh中
(1)在命令行定义
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 的元素。
(2)在脚本文件中定义
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语句来指定脚本解释器。
2.在sh中
(1)在命令行定义
csdn \~$ exec sh
sh-4.2$ a=(1 'a' b)
sh-4.2 echo a
1
sh-4.2$

(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$

3.在bash中
(1)在命令行定义
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个元素,而不是所有元素。
(2)在脚本文件中定义
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个元素,而不是所有元素。
(二)数组名下标=数值
1.在zsh中
(1)在命令行定义
csdn @edu in ~ ++b0=0++
zsh: b: assignment to invalid subscript range
csdn @edu in ~ ++b1=1++
csdn @edu in ~ ++b2=a++
csdn @edu in ~ ++echo $b++
1 a
csdn @edu in ~

在上面的例子中,我们首先尝试直接在命令行定义数组元素:++b0=0++,但是zsh提示下标超出范围。
接下来,我们的命令 ++b1=1++ 和 ++b2=a++ 顺利完成,最后我们用命令 ++echo $b++显示 数组b的2个元素值:1 a。
可见,在zsh中,数组元素的下标是从1开始的。
(2)在脚本文件中定义
$ ++echo 'b0=0' > b.sh++
csdn @ edu in ~ 22:07:01
$ ++echo 'b1=1' >> b.sh++
csdn @ edu in ~ 22:07:24
$ ++echo 'b2=a' >> b.sh++
csdn @ edu in ~ 22:07:39
++echo 'echo b' >> b.sh++
csdn @ edu in ~ 22:08:05
$ ++cat b.sh++
b0=0
b1=1
b2=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 + 输出重定向方式将数组定义语句
b0=0
b1=1
b2=a
然后 我们将 显示数组元素 的命令 ++echo 'echo $b' >> b.sh++写入脚本文件b.sh
随后我们使用命令 ++cat b.sh++ 查看脚本文件b.sh 的内容:
b0=0
b1=1
b2=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开始的。
2.在sh中
(1)在命令行中定义
csdn @edu in ~ ++exec sh++
sh-4.2$ ++b0=0++
sh-4.2$ ++b1=1++
sh-4.2$ ++b2=a++
sh-4.2 ++echo b++
0
sh-4.2$

数组成功创建,但只看到了数组中的第1个元素值。
(2)在脚本文件中定义
sh-4.2$ echo 'b0=0' > b.sh
sh-4.2$ echo 'b1=1' >> b.sh
sh-4.2$ echo 'b2=a' >> b.sh
sh-4.2 echo 'echo b' >> b.sh
sh-4.2$ cat b.sh
b0=0
b1=1
echo $b
sh-4.2$ source ./b.sh
0
sh-4.2$

我们先使用echo + 输出重定向方式将数组定义语句
b0=0
b1=1
b2=a
然后 我们将 显示数组元素 的命令 ++echo 'echo $b' >> b.sh++写入脚本文件b.sh
随后我们使用命令 ++cat b.sh++ 查看脚本文件b.sh 的内容:
b0=0
b1=1
b2=a
echo $b
最后我们使用 ++source ./b. sh++ 命令来执行脚本文件b.sh,数组成功创建,但只看到了数组中的第1个元素值。
3.在bash中
(1)在命令行中定义
csdn @ edu in ~ 23:53:42
$ exec bash
csdn \~ echo 0
bash
csdn \~$ b0=0
csdn \~$ b1=1
csdn \~$ b2=a
csdn \~ echo b
0
csdn \~$

命令全部顺利执行,可见在bash中,数组元素的下标是从0开始的,但echo $b只显示了数组第1个元素值。
(2)在脚本文件中定义
csdn \~$ echo b0=0 > b.sh
csdn \~$ echo b1=1 >> b.sh
csdn \~$ echo b2=a >> b.sh
csdn \~ echo 'echo b' >> b.sh
csdn \~$ cat b.sh
b0=0
b1=1
b2=a
echo $b
csdn \~$ . b.sh
0
csdn \~$

在脚本文件中执行跟 命令行执行结果是一样的。
(三)小结
在zsh中,数组元素的下标是从 1 开始的,使用"$数组名" 可以获得数组所有元素值。
在sh和bash中,数组元素的下标是从 0 开始的,使用"$数组名" 只能获得数组第1个元素值。
三、获取所有的数组元素
通过上面的实例,我们发现在sh和bash中,使用"$数组名" 只能获得数组第1个元素值,那么如何获取所有的数组元素呢?我们可以使用* 或 @ 作为下标来获取,具体格式即:
${数组名@}
或
${数组名\*}
(一)zsh中
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
$

(二)在sh中
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$

(三)在bash中
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 \~$
四、获取数组或数组元素的长度
在介绍字符串时,我们说过获取字符串的格式是:${#字符串名},获取数组或数组元素长度的格式是相似的:
${#数组名下标}
或
${#数组名下标}
如果要取数组的长度,那么下标就用*或 @。如果要取数组某个元素的长度,那么下标就用元素的下标。
(一)在zsh中
csdn @ edu in ~ 12:57:21
++echo 0++
/bin/zsh
csdn @ edu in ~ 12:57:24
$ ++b1=1++
csdn @ edu in ~ 12:57:31
$ ++b2=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 {b0}
csdn @ edu in ~ 12:58:07
echo {#b0}
0
csdn @ edu in ~ 12:58:11
echo {b1}
1
csdn @ edu in ~ 12:58:26
echo {#b1}
1
csdn @ edu in ~ 12:58:30
echo {b2}
22
csdn @ edu in ~ 12:58:35
echo {#b2}
2

(二)sh中
csdn @ edu in ~ 13:07:28
$ ++exec sh++
sh-4.2$ ++b1=1++
sh-4.2$ ++b2=22++
sh-4.2 ++echo {b\*}++
1 22
sh-4.2 ++echo {#b\*}++
2
sh-4.2 ++echo {#b@}++
2
sh-4.2 echo ++{b0}++
sh-4.2 echo ++{#b0}++
0
sh-4.2 echo ++{b1}++
1
sh-4.2 echo ++{#b1}++
1
sh-4.2 echo ++{b2}++
22
sh-4.2 echo ++{#b2}++
2
sh-4.2$

(三)bash中
csdn \~$ b1=1
csdn \~$ b2=22
csdn \~ echo {b@}
1 22
csdn \~ echo {#b@}
2
csdn \~ echo {#b\*}
2
csdn \~ echo {b0}
csdn \~ echo {#b0}
0
csdn \~ echo {b1}
1
csdn \~ echo {#b1}
1
csdn \~ echo {b2}
22
csdn \~ echo {#b2}
2
csdn \~$

在上面的实例中,由于zsh中数组元素下标是从1开始的,所以我们定义数组b时,是从下标为1 的元素开始的。
然后我们先获取整个数组的元素值和长度,然后从下标0开始获取数组每个元素的值和长度。
值得注意的是,我们使用命令 echo {b\[0\]} 尝试显示数组b中下标为0 的元素值 时,系统没有提示出错;使用命令echo {#b0}尝试显示数组b中下标为0 的元素的长度时,系统反馈为0。