假设我有以下2个阵列。数组总是按字母顺序排序。
arr1=(a b c)
arr2=(a b c d)
我必须比较这两个数组,如果它们完全相同,则必须返回true。
答案 0 :(得分:9)
我找到了一个可能的解决方案,使用STDIN和diff:
#!/bin/bash
arr1=(a b c)
arr2=(a b c d)
diff=$(diff <(printf "%s\n" "${arr1[@]}") <(printf "%s\n" "${arr2[@]}"))
if [[ -z "$diff" ]]; then
echo "TRUE"
else
echo "FALSE"
fi
编辑: 一点解释:
它会从数组中生成一个字符串,并通过STDIN将它们提供给diff。 diff
或者返回差异或者没有任何内容,我将其填入变量并稍后使用-z测试内容。
答案 1 :(得分:7)
由于"$*"
将所有位置参数作为单个单词获取,因此可以实现:
[ "${arr1[*]}" == "${arr2[*]}" ] && echo "equal" || echo "distinct"
请注意,表达式[ condition ] && echo "equal" || echo "distinct"
等同于
if [ condition ]; then
echo "equal"
else
echo "distinct"
fi
$ arr1=(a b c)
$ arr2=(a b c d)
$ [ "${arr1[*]}" == "${arr2[*]}" ] && echo "equal" || echo "distinct"
distinct
$ arr2=(a b c)
$ [ "${arr1[*]}" == "${arr2[*]}" ] && echo "equal" || echo "distinct"
equal
当元素没有空格时,它只能100%工作(参见注释中的讨论)。
答案 2 :(得分:3)
我能想到的最强大的方式是:
所以:
arr1=(1 2 3 )
arr2=(1 2 "3 4")
[ ${#arr1[*]} != ${#arr2[*]} ] && { echo arrays different size; exit 1; }
for ii in ${!arr1[*]}; do
[ "${arr1[$ii]}" == "${arr2[$ii]}" ] || { echo different element $ii; exit 1; }
done
echo arrays identical
exit 0
使用的构造是:
${#array[*]}
返回数组中元素的数量${!array[*]}
返回索引列表(而不是返回元素的${array[*]}
)上面应该处理数组值,稀疏数组和关联数组中的空格(虽然它不总是捕获关联数组中的不同索引,但是你需要额外的测试)。
答案 3 :(得分:2)
对于那些想要使用函数而不是直接检查的解决方案的人来说,这是我写的解决方案。后者适用于普通数组,关联数组和稀疏数组。但它至少需要Bash 4.3。
这个函数是我写的lib的一部分。作为我的lib中的约定,我使用返回值和retval
全局参数来表示比简单数字更复杂的return语句。这同样适用于errorWithLog
,它只是stderr
上的回显,如果后者可用,则记录为系统记录器的错误。
#-------------------------------------------------------------------------------
# I: - The array to compare tableA[@]
# - The second array tableB[@] against which to compare the first array
# P: Search if both arrays (all types) are equal
# NOTE: The tables must be passed *AS NAME* as myTable not as $myTable[@]
# nor ${myTable[@]} and requires Bash 4.3
# Inspired from http://stackoverflow.com/a/17990637/3514658
# and from http://stackoverflow.com/a/4017175/3514658
# O: - If both arrays are equal:
# - retval: true
# - return value for direct usage in a if statement: 0
# - If both arrays are not equal:
# - retval: false
# - return value for direct usage in a if statement: 1
#-------------------------------------------------------------------------------
function isArraysEqual() {
# Accessing by dereference using -n is new in Bash 4.3.
local -n arr1=$1 2>/dev/null
local -n arr2=$2 2>/dev/null
# If <Bash 4.3, need to use the following syntax, but checking the keys of
# associative arrays is not supported and, in that case, tables must be
# passed as names *WITH* elements i.e.: myTable[@]
# local -a arr1=("${!1}")
# local -a arr2=("${!2}")
if [ $? -ne 0 ]; then
errorWithLog "isArraysEqual() accessing using dereference with -n"\
"needs at least Bash 4.3. Arrays reported as different."
retval=false
return 1
fi
# Check size first. This is way faster than checking each item over
# iteration.
if [ ${#arr1[@]} != ${#arr2[@]} ]; then
retval=false
return 1
fi
# The ! expands to a list of array keys. For normal arrays, not associative
# arrays, this gives a list of index values starting from 0.
local -a arr1Keys=("${!arr1[@]}")
local -a arr2Keys=("${!arr2[@]}")
for (( i = 0; i < ${#arr1[@]}; i += 1 )); do
key=${arr1Keys[$i]}
# Check if the values are the same. If the key does not exist in arr2
# and the key does exist but is null in arr1, the values are NOT
# considered different. This is why checking keys is mandatory.
if [ "${arr1[$key]}" != "${arr2[$key]}" ]; then
retval=false
return 1
fi
# Check if keys are the same. This is needed for associative arrays.
if [ "${arr1Keys[$i]}" != "${arr2Keys[$i]}" ]; then
retval=false
return 1
fi
done
retval=true
return 0
}
用法示例:
declare -A table1=([hello]=world [ab]=cd)
declare -A table2=([hello]=world [ab]=cd)
if isArraysEqual table1[@] table2[@]; then
echo "yes"
else
echo "no"
fi
提供yes
。
declare -A table1=([hello]=world [ab]=cd)
declare -A table2=([hello]=world [ab]=cde)
if isArraysEqual table1 table2; then
echo "yes"
else
echo "no"
fi
提供no
。
declare -A table1=([hello]=world [abhe]=ce)
declare -A table2=([hello]=world [ab he]=ce)
if isArraysEqual table1 table2; then
echo "yes"
else
echo "no"
fi
提供no
。
table1=(1 2 3 4)
table2=(1 2 "3 4")
if isArraysEqual table1 table2; then
echo "yes"
else
echo "no"
fi
提供no
。