注意事项
并不是每种 Shell 都支持数组(比如 Bash 支持数组,但是 Dash 不支持数组),为了写出可移植脚本,不建议使用数组。
The Bourne shell or the Unix sh lanuage specification don't support arrays.
定义 - 如何定义一个数组?
索引数组
# 声明索引数组 declare -a mIndexArray # 索引数组也可以直接定义: mIndexArray=(one two three)
关联数组
# 声明关联数组 declare -A mAssociativeArray # 但是,关联数组不可以直接定义,必须先声明: declare -A mAssociativeArray mAssociativeArray=( [foo]=bar [baz]=quux [corge]=grault ) # 如果没有先声明为关联数组,则 mAssociativeArray=( [foo]=bar [baz]=quux [corge]=grault ) 默认为索引数组,并且其中的元素也发生了变化。
赋值 - 如何对数组进行赋值?
对索引数组和关联数组进行赋值方面,两者直接并无太大差异:
mIndexArray[5]=five mAssociativeArray[five]=five
数组索引也可以是变量:
mAssociativeArray[$var]=value
即使索引是“存在空格的字符串”,也不需要引用:
# 下面三种是等价的 mAssociativeArray['key with space']=value mAssociativeArray["key with space"]=value mAssociativeArray[key with space]=value
也可以使用如下方式,以无需索引的方式向数组中添加元素:
# 如下示例向索引数组mIndexArray中添加了两个元素,但是无需指定索引 mIndexArray=() mIndexArray+=('foo') mIndexArray+=('bar')
取值 - 如何取值及打印整个数组?
从数组中取值
对索引数组和关联数组进行取值方面,两者直接并无太大差异:
echo ${mIndexArray[5]} echo ${mAssociativeArray[five]} echo ${mArray[$var]} ehco ${mArray[var with space]}
打印整个数组
打印整个数组的方式有些特殊。下面的这个做法是错误的:
# 如下示例,索引数组只会打印第一个元素,而关联数组则输出空 echo $mIndexArray echo $mAssociativeArray
打印数组的全部元素的正确形式应该是:
# 如下的两种形式并无差异,但打印的都是数组中值,并不包含索引 echo ${mIndexArray[*]} echo ${mAssociativeArray[*]} echo ${mIndexArray[@]} echo ${mAssociativeArray[@]}
如果要打印索引,则应该:
# 如下示例将打印数组的所有索引 echo ${!mIndexArray[*]} echo ${!mAssociativeArray[*]} echo ${!mIndexArray[@]} echo ${!mAssociativeArray[@]}
使用循环打印整个数组
上面的示例已经能够获取数组的索引和值了,所以循环也不会很麻烦:
如下示例分别演示了打印数组索引和值的方法:
for key in "${!mAssociativeArray[@]}" do echo $key echo ${mAssociativeArray[$key]} done for value in "${mAssociativeArray[@]}" do echo $value done for value in "${mIndexArray[@]}" do echo $value done
如何判断某个索引是否存在?
使用常用的 if 语句即可。如下,如果找到了索引,则打印“Found”字符串:
if [ ${mAssociativeArray[$var]} ] then echo "Found" else echo "Not found" fi
删除 - 如何删除数组及其中某个元素?
删除数组
如果要删除一个关联数组或者索引数组,可以进行unset操作:
unset mAssociativeArray unset mIndexArray
注意事项:重新声明(declare)并不能删除覆盖原有的数组;指定要删除的数组时,没有美元($)符号;
删除元素
删除元素只需要指定数组中元素即可:
unset mAssociativeArray[key] unset mIndexArray[0]
注意事项:指定要删除的数组元素时,没有美元($)符号;索引数组中元素的索引也不会前移(例如,删除索引为3的元素,那索引为4的元素的索引不会变为3)。
删除元素时,如果索引中包含空格
如果删除元素的索引包含空格则需要进行引用,这里比较特殊:
unset mAssociativeArray["key with space"] unset mAssociativeArray["$var"]
这里比较特殊的。与取值、赋值时“即使存在空格也无需引用”的情形有些不同。
长度 - 如何获取数组的长度?
使用井号(#)来获取数组的长度,形式如下:
echo ${#mIndexArray[*]} echo ${#mAssociativeArray[*]} echo ${#mIndexArray[@]} echo ${#mAssociativeArray[@]}
这种用法也可以用于计算字符串的长度。
传参 - 如何将数组作为函数参数传递?
这一点就比较奇怪了,如果要讲数组传递到函数里,有两个办法:
1)定义一个全局的数组;
2)或者,将数组的值全部传递到函数中,然后在函数组使用$@取到所有值,然后放在函数中的一个数组中。
目前,我还没有找到直接传递数组的方法。 参考「How to pass an array as function argument?」文章。
拼接 - 拼接数组元素
特殊场景:我们可以换个思路,使用 seq 命令,生成有规律的数据:
# seq -s ', ' -f '192.168.1.%.0f:2000' 10 15 192.168.1.10:2000, 192.168.1.11:2000, 192.168.1.12:2000, 192.168.1.13:2000, 192.168.1.14:2000, 192.168.1.15:2000
注意事项
奇怪的作用域
函数隐式创建的数组,将作用与全局:
unset mAssociativeArray function createWithoutDeclare() { mAssociativeArray[foo]=bar; } echo ${mAssociativeArray[foo]} createWithoutDeclare echo ${mAssociativeArray[foo]}
函数显式创建的数组,将作用于本地:
unset mAssociativeArray function createWithDeclare() { declare -A mAssociativeArray[foo]=bar; } echo ${mAssociativeArray[foo]} createWithDeclare echo ${mAssociativeArray[foo]}
这一特性是 declare 导致的,也不足为奇怪,可以参考declare的说明(执行help decalre命令来查看,因为declare是Bash的内建命令)。
在 Dash 中,使用数组
#!/bin/sh var="this is a test|second test|the quick brown fox jumped over the lazy dog" oldIFS=$IFS IFS="|" set -- $var echo "$1" echo "$2" echo "$3" # Note: if more than $9 you need curly braces e.g. "${10}" IFS=$oldIFS
参考文献
Add a new element to an array without specifying the index in Bash
How to pass an array as function argument?
Bash associative array examples
Does `dash` support `bash` style arrays?
Looping over arrays, printing both index and value
Arrays in Unix Bourne Shell - Unix & Linux Stack Exchange