Skip to content

Instantly share code, notes, and snippets.

@gotnix
Last active July 2, 2018 09:53
Show Gist options
  • Save gotnix/9402248526405c87a415ee511bb9a696 to your computer and use it in GitHub Desktop.
Save gotnix/9402248526405c87a415ee511bb9a696 to your computer and use it in GitHub Desktop.
Bash 的数组

数组和关联数组(associative array)的初始化语法类似。

# 定义数组
declare -a array=(alpha beta omega)

# 定义关联数组
declare -A dict=(
	[key1]=alpha
	[key2]=beta
	[key3]=omega
	[key4]=''
)

取 length、Key、Value 的操作都一样,数组和关联数组没有区别。

echo "# 取长度"
echo ${#dict[*]}
echo ${#dict[@]}

echo "# 取所有 Key"
echo ${!dict[*]}
echo ${!dict[@]}

echo "# 取所有 Value"
echo ${dict[*]}
echo ${dict[@]}

判断数组是否包含一个元素,最简便的方法是通过数组的 Substring Replacement,请参考

echo '# 检查数组是否包含一个元素'
[[ "${array[@]/omega/}" != "${array[@]}" ]] && echo "in" || echo "not in"
[[ "${array[@]/gamma/}" != "${array[@]}" ]] && echo "in" || echo "not in"

检查一个关联数组是否包含某个 Key,和检查一个变量是否设置的方法类似,使用 Parameter Expansion${parameter+word},参考 Test if element is in array in bash, ${parameter+word} 的用法请参考 Use an alternate value,基本上Bash 的 Parameter Expansion 都是判断变量是否设置,已经设置了值是否为空。

echo "# 检查关联数组 key 是否存在(允许 Value 为空)"
if [[ -n "${dict[${key_name}]+X}" ]]; then
	printf '%s\n' "$key_name is in Array."
else
	printf '%s\n' "$key_name isn't in Array."
fi

遍历数组也都一样。其实数组也是有 Key 的,直接用下面遍历关联数组的命令,遍历一下普通数组就能看到从 0 开始的索引。

echo "# 遍历数组"
for i in ${array[@]}; do
	echo $i
done

echo "# 遍历关联数组"
for key in ${!dict[@]}; do
	printf "%-5s: %-6s\n" $key ${dict[${key}]};
done

数组的间接引用和使用数组作为行参

array_fun.sh
declare -a g_ary=( 1 2 3 )
a () {
    declare -a ary=${!1}
    ary+=(4)
    echo ${ary[@]}
    unset ary
}

a g_ary[@]
echo ${g_ary[@]}

遍历数组的其它特殊情况

$ » for i in "${a1[@]}"; do echo "${i}." ; done
a.
 .
.
null.

$ » for i in ${a1[@]}; do echo "${i}". ; done
a.
null.

$ » declare -a a2
$ » for (( i=0; i <= ${#a2[@]}; i=i+1 )) ; do echo "${i} : ${a2[${i}]}."; done
-bash: a2[${i}]: unbound variable

$ » for i in "${a2[@]}"; do echo "${i}." ; done
-bash: a2[@]: unbound variable

Bash 的 nounset 属性和空数组

unset_array.sh
#!/bin/bash
#
set -o nounset

declare -a ary=( $(find /tmp/ -depth -mindepth 1 -maxdepth 1 -type d -mtime +1 -printf  "%P ") )  # (1)

for (( i = 0 ; i < ${#ary[@]} ; i=i+1 ))  # (2)
do
        if [[ -n ${ary[${i}]} ]]
        then
                echo ${ary[${i}]}
        fi
done

for i in ${ary[@]}  # (3)
do
        if [[ -n ${i} ]]
        then
                echo ${i}
        fi
done

declare -a a1=( 'a' ' ' '' 'null' )  # (4)
for (( i=0; i <= ${#a1[@]}; i=i+1 ))
do
	if [[ -n ${a1[${i}]} ]]
	then
		echo "${i} : ${a2[${i}]}."
	fi
done
  1. 如果 find 命令没有输出,则数组 ary 的值为空。

  2. 这里的 for 循环取长度的操作可能是因为只取长度,不需要展开数组求值,再加循环体里面的 if 语句,也不会对数组元素求职,这种写法不受 nounset 影响。

  3. 因为开启了 nounset 属性, 这里的 for 循环会在结束之后提示 unbound variable 退出脚本。

  4. 如果数组元素的值是空格( ' ')是不受 nounset 限制的,但是元素的值为空字符串( '' ),还是会报 unbound variable ,脚本在执行完 for 循环之后中止退出;由于空格还是会执行 for 循环,最好还是给变量加上双引号。

更多用法请参考 ABS Chapter 27. Arrays

@cherrot
Copy link

cherrot commented Jul 9, 2017

解释的很细致,感谢!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment