「Shell」- 数组的使用 @20210124

本文详细介绍了Bash shell中数组的定义、赋值、取值、删除、长度计算、传递以及特殊作用域等操作,并对比了不支持数组的Dash。还提到了在数组操作中关于空格处理的注意事项,以及如何在特定场景下利用seq命令生成数据。最后,文章揭示了在函数中使用数组的奇怪作用域现象,并提供了在Dash中处理类似问题的方法。

注意事项

并不是每种 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+=('foo')
# mIndexArray+=('bar')

 

上面的示例向索引数组mIndexArray中添加了两个元素,但是无需指定索引。

取值 - 如何取值及打印整个数组?

从数组中取值

对索引数组和关联数组进行取值方面,两者直接并无太大差异:

 

# 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语句即可:

 

if [ ${mAssociativeArray[$var]} ]
then echo "Found"
else
echo "Not found"
fi

 

如果找到了索引,则打印“Fount”字符串。

删除 - 如何删除数组及其中某个元素?

删除数组

如果要删除一个关联数组或者索引数组,可以进行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[@]}

 

这种用法也可以用于计算字符串的长度。

传参 - 如何将数组作为函数参数传递?

这一点就比较奇怪了,如果要讲数组传递到函数里,有两个办法:

 

定义一个全局的数组;
或者,将数组的值全部传递到函数中,然后在函数组使用$@取到所有值,然后放在函数中的一个数组中。

 

目前,我还没有找到直接传递数组的方法。 参考「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

参考文献

WikiNotes/数组的使用
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

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值