使用 shell 脚本比较两个不同的数组
Comparing two different arrays using shell script
我们如何比较两个数组并在 shell 脚本中显示结果?
假设我们有如下两个数组:
list1=( 10 20 30 40 50 60 90 100 101 102 103 104)
list2=( 10 20 30 40 50 60 70 80 90 100 )
我的要求是按顺序比较这两个数组,这样它只会显示 (101 102 103 104)
来自 list1
的结果。它不应包括存在于 list2
但不存在于 list1
中的值 70
和 80
。
这无济于事,因为它包含了所有内容:
echo "${list1[@]}" "${list2[@]}" | tr ' ' '\n' | sort | uniq -u
我在下面尝试过类似的方法,但为什么它不起作用?
list1=( 10 20 30 40 50 60 70 90 100 101 102 103 104)
list2=( 10 20 30 40 50 60 70 80 90 100 )
for (( i=0; i<${#list1[@]}; i++ )); do
for (( j=0; j<${#list2[@]}; j++ )); do
if [[ ${list1[@]} == ${list2[@] ]]; then
echo 0
break
if [[ ${#list2[@]} == ${#list1[@]-1} && ${list1[@]} != ${list2[@]} ]];then
echo ${list3[$i]}
fi
fi
done
done
您可以为此使用 comm
:
readarray -t unique < <( \
comm -23 \
<(printf '%s\n' "${list1[@]}" | sort) \
<(printf '%s\n' "${list2[@]}" | sort) \
)
导致
$ declare -p unique
declare -a unique=([0]="101" [1]="102" [2]="103" [3]="104")
或者,要获得您想要的格式,
$ printf '(%s)\n' "${unique[*]}"
(101 102 103 104)
comm -23
接受两个排序的文件(使用 sort
here) and prints every line that is unique to the first one; process substitution 用于将列表输入 comm
。
然后,readarray
读取输出并将每一行放入 unique
数组的一个元素中。 (注意这需要 Bash。)
您的尝试失败,除其他外,因为您试图在单次比较中比较多个元素:
[[ ${list1[@]} != ${list2[@]} ]]
扩展到
[[ 10 20 30 40 50 60 90 100 101 102 103 104 != 10 20 30 40 50 60 70 80 90 100 ]]
和 Bash 抱怨预期的二元运算符而不是第二个元素 20
.
ksh 关联数组对此很方便:
list1=( 10 20 30 40 50 60 90 100 101 102 103 104)
list2=( 10 20 30 40 50 60 70 80 90 100 )
typeset -a onlyList1
typeset -A inList2
for elem in "${list2[@]}"; do inList2["$elem"]=1; done
for elem in "${list1[@]}"; do [[ -v inList2["$elem"] ]] || onlyList1+=("$elem"); done
typeset -p onlyList1
typeset -a onlyList1=(101 102 103 104)
或者类似地,从所有 list1 开始并删除 list2 中的内容:
typeset -A inList1
for elem in "${list1[@]}"; do inList1["$elem"]=1; done
for elem in "${list2[@]}"; do unset inList1["$elem"]; done
onlyList1=( "${!inList1[@]}" )
也可以用这种方法
#!/bin/ksh
list1=( 10 20 30 40 50 60 90 100 101 102 103 104 )
list2=( 10 20 30 40 50 60 70 80 90 100 )
# Creating a temp array with index being the same as the values in list1
for i in ${list1[*]}; do
list3[$i]=$i
done
# If value of list2 can be found in list3 forget this value
for j in ${list2[*]}; do
if [[ $j -eq ${list3[$j]} ]]; then
unset list3[$j]
fi
done
# Print the remaining values
print ${list3[*]}
输出是
101 102 103 104
希望对您有所帮助
编辑
如果两个列表相同:
# Print the remaining values
if [[ ${#list3[*]} -eq 0 ]]; then
print "No differences between the list"
else
print ${list3[*]}
fi
我们如何比较两个数组并在 shell 脚本中显示结果?
假设我们有如下两个数组:
list1=( 10 20 30 40 50 60 90 100 101 102 103 104)
list2=( 10 20 30 40 50 60 70 80 90 100 )
我的要求是按顺序比较这两个数组,这样它只会显示 (101 102 103 104)
来自 list1
的结果。它不应包括存在于 list2
但不存在于 list1
中的值 70
和 80
。
这无济于事,因为它包含了所有内容:
echo "${list1[@]}" "${list2[@]}" | tr ' ' '\n' | sort | uniq -u
我在下面尝试过类似的方法,但为什么它不起作用?
list1=( 10 20 30 40 50 60 70 90 100 101 102 103 104)
list2=( 10 20 30 40 50 60 70 80 90 100 )
for (( i=0; i<${#list1[@]}; i++ )); do
for (( j=0; j<${#list2[@]}; j++ )); do
if [[ ${list1[@]} == ${list2[@] ]]; then
echo 0
break
if [[ ${#list2[@]} == ${#list1[@]-1} && ${list1[@]} != ${list2[@]} ]];then
echo ${list3[$i]}
fi
fi
done
done
您可以为此使用 comm
:
readarray -t unique < <( \
comm -23 \
<(printf '%s\n' "${list1[@]}" | sort) \
<(printf '%s\n' "${list2[@]}" | sort) \
)
导致
$ declare -p unique
declare -a unique=([0]="101" [1]="102" [2]="103" [3]="104")
或者,要获得您想要的格式,
$ printf '(%s)\n' "${unique[*]}"
(101 102 103 104)
comm -23
接受两个排序的文件(使用 sort
here) and prints every line that is unique to the first one; process substitution 用于将列表输入 comm
。
然后,readarray
读取输出并将每一行放入 unique
数组的一个元素中。 (注意这需要 Bash。)
您的尝试失败,除其他外,因为您试图在单次比较中比较多个元素:
[[ ${list1[@]} != ${list2[@]} ]]
扩展到
[[ 10 20 30 40 50 60 90 100 101 102 103 104 != 10 20 30 40 50 60 70 80 90 100 ]]
和 Bash 抱怨预期的二元运算符而不是第二个元素 20
.
ksh 关联数组对此很方便:
list1=( 10 20 30 40 50 60 90 100 101 102 103 104)
list2=( 10 20 30 40 50 60 70 80 90 100 )
typeset -a onlyList1
typeset -A inList2
for elem in "${list2[@]}"; do inList2["$elem"]=1; done
for elem in "${list1[@]}"; do [[ -v inList2["$elem"] ]] || onlyList1+=("$elem"); done
typeset -p onlyList1
typeset -a onlyList1=(101 102 103 104)
或者类似地,从所有 list1 开始并删除 list2 中的内容:
typeset -A inList1
for elem in "${list1[@]}"; do inList1["$elem"]=1; done
for elem in "${list2[@]}"; do unset inList1["$elem"]; done
onlyList1=( "${!inList1[@]}" )
也可以用这种方法
#!/bin/ksh
list1=( 10 20 30 40 50 60 90 100 101 102 103 104 )
list2=( 10 20 30 40 50 60 70 80 90 100 )
# Creating a temp array with index being the same as the values in list1
for i in ${list1[*]}; do
list3[$i]=$i
done
# If value of list2 can be found in list3 forget this value
for j in ${list2[*]}; do
if [[ $j -eq ${list3[$j]} ]]; then
unset list3[$j]
fi
done
# Print the remaining values
print ${list3[*]}
输出是
101 102 103 104
希望对您有所帮助
编辑
如果两个列表相同:
# Print the remaining values
if [[ ${#list3[*]} -eq 0 ]]; then
print "No differences between the list"
else
print ${list3[*]}
fi