假设我有以下 2 个数组。数组始终按字母顺序排序。
arr1=(a b c)
arr2=(a b c d)
我必须比较这两个数组,如果它们完全相同,则必须返回 true。
我为您找到了一个可能的解决方案,使用 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 测试内容。
将所有位置参数作为"$*"
一个单词获取,这可以使它:
[ "${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% 工作(参见评论中的讨论)。
我能想到的最稳健的方法是:
所以:
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[*]}
返回元素)上面应该处理数组值、稀疏数组和关联数组中的空白(尽管它并不总是捕获关联数组中的不同索引,但您需要对此进行额外的测试)。
对于那些想要使用函数而不是直接检查的解决方案的人,这是我编写的解决方案。后者适用于普通数组、关联数组和稀疏数组。但它至少需要 Bash 4.3。
这个函数是我写的库的一部分。作为我的库中的约定,我使用返回值和retval
全局参数来表示比简单数字更复杂的返回语句。这同样适用于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
.