linux shell 数组对比,bash中两个数组的比较/差异

bash中两个数组的比较/差异

是否有可能采取bash中两个数组的差异。

如果您可以建议我这样做的话,那真的很棒。

代码:

Array1=( "key1" "key2" "key3" "key4" "key5" "key6" "key7" "key8" "key9" "key10" )

Array2=( "key1" "key2" "key3" "key4" "key5" "key6" )

Array3 =diff(Array1, Array2)

Array3 ideally should be :

Array3=( "key7" "key8" "key9" "key10" )

感谢你的帮助。

7个解决方案

105 votes

echo ${Array1[@]} ${Array2[@]} | tr ' ' '\n' | sort | uniq -u

输出量

key10

key7

key8

key9

您可以根据需要添加排序

Ilya Bystrov answered 2020-06-23T08:27:10Z

28 votes

如果您严格想要key1 < … < key9 > key10,那么

Array1=( "key1" "key2" "key3" "key4" "key5" "key6" "key7" "key8" "key9" "key10" )

Array2=( "key1" "key2" "key3" "key4" "key5" "key6" )

Array3=()

for i in "${Array1[@]}"; do

skip=

for j in "${Array2[@]}"; do

[[ $i == $j ]] && { skip=1; break; }

done

[[ -n $skip ]] || Array3+=("$i")

done

declare -p Array3

关联数组可能会改善运行时,但是我个人不会打扰。 如果要处理足够多的数据,那么shell是错误的工具。

对于像丹尼斯答案这样的对称差异,只要我们对输入和输出进行一点点按摩即可使用现有的工具,例如key1 < … < key9 > key10(因为它们适用于基于行的文件,而不适用于shell变量)。

在这里,我们告诉shell使用换行符将数组连接成一个字符串,并在将key1 < … < key9 > key10中的行读回到数组中时放弃制表符。

$ oldIFS=$IFS IFS=$'\n\t'

$ Array3=($(comm -3

comm: file 1 is not in sorted order

$ IFS=$oldIFS

$ declare -p Array3

declare -a Array3='([0]="key7" [1]="key8" [2]="key9" [3]="key10")'

它之所以抱怨是因为按字典顺序排序为key1 < … < key9 > key10。但是由于两个输入数组的排序方式都相似,因此可以忽略该警告。 您可以使用--nocheck-order摆脱警告,或者,如果不能保证输入数组的顺序和唯一性,则可以在

ephemient answered 2020-06-23T08:26:46Z

15 votes

每当出现一个问题,处理可能无法排序的唯一值时,我的脑子立刻就醒悟。 这是我的看法。

#!/bin/bash

diff(){

awk 'BEGIN{RS=ORS=" "}

{NR==FNR?a[$0]++:a[$0]--}

END{for(k in a)if(a[k])print k}'

}

Array1=( "key1" "key2" "key3" "key4" "key5" "key6" "key7" "key8" "key9" "key10" )

Array2=( "key1" "key2" "key3" "key4" "key5" "key6" )

Array3=($(diff Array1[@] Array2[@]))

echo ${Array3[@]}

输出量

$ ./diffArray.sh

key10 key7 key8 key9

*注意**:像给出的其他答案一样,如果数组中有重复的键,则它们只会被报告一次; 这可能是或不是您正在寻找的行为。 用于处理该问题的awk代码更加混乱,而且不够干净。

SiegeX answered 2020-06-23T08:27:45Z

6 votes

在Bash 4中:

declare -A temp # associative array

for element in "${Array1[@]}" "${Array2[@]}"

do

((temp[$element]++))

done

for element in "${!temp[@]}"

do

if (( ${temp[$element]} > 1 ))

then

unset "temp[$element]"

fi

done

Array3=(${!temp[@]}) # retrieve the keys as values

编辑:

暂时性指出了潜在的严重错误。 如果一个元素存在于一个数组中且具有一个或多个重复项,而根本不存在于另一个数组中,则该元素将被错误地从唯一值列表中删除。 下面的版本试图解决这种情况。

declare -A temp1 temp2 # associative arrays

for element in "${Array1[@]}"

do

((temp1[$element]++))

done

for element in "${Array2[@]}"

do

((temp2[$element]++))

done

for element in "${!temp1[@]}"

do

if (( ${temp1[$element]} >= 1 && ${temp2[$element]-0} >= 1 ))

then

unset "temp1[$element]" "temp2[$element]"

fi

done

Array3=(${!temp1[@]} ${!temp2[@]})

Dennis Williamson answered 2020-06-23T08:28:14Z

6 votes

将comm和array_intersect作为参数,使用comm来完成工作,并使用mapfile将其放回RESULT数组中:

ARR1=("key1" "key2" "key3" "key4" "key5" "key6" "key7" "key8" "key9" "key10")

ARR2=("key1" "key2" "key3" "key4" "key5" "key6")

mapfile -t RESULT < \

)

echo "${RESULT[@]}" # outputs "key10 key7 key8 key9"

请注意,结果可能不符合源顺序。

额外的奖励,“这就是您在这里的目的”:

function array_diff {

eval local ARR1=\(\"\${$2[@]}\"\)

eval local ARR2=\(\"\${$3[@]}\"\)

local IFS=$'\n'

mapfile -t $1 <

}

# usage:

array_diff RESULT ARR1 ARR2

echo "${RESULT[@]}" # outputs "key10 key7 key8 key9"

在处理bash中传递的数组参数中,使用那些棘手的评估是最糟糕的选择。

另外,请查看comm的联机帮助页; 根据此代码,它很容易实现,例如array_intersect:只需使用-12作为comm选项。

Alex Offshore answered 2020-06-23T08:28:52Z

3 votes

也可以使用正则表达式(基于另一个答案:bash中的数组交集):

list1=( 1 2 3 4 6 7 8 9 10 11 12)

list2=( 1 2 3 5 6 8 9 11 )

l2=" ${list2[*]} " # add framing blanks

for item in ${list1[@]}; do

if ! [[ $l2 =~ " $item " ]] ; then # use $item as regexp

result+=($item)

fi

done

echo ${result[@]}:

结果:

$ bash diff-arrays.sh

4 7 10 12

Denis Gois answered 2020-06-23T08:29:16Z

2 votes

Array1=( "key1" "key2" "key3" "key4" "key5" "key6" "key7" "key8" "key9" "key10" )

Array2=( "key1" "key2" "key3" "key4" "key5" "key6" )

Array3=( "key1" "key2" "key3" "key4" "key5" "key6" "key11" )

a1=${Array1[@]};a2=${Array2[@]}; a3=${Array3[@]}

diff(){

a1="$1"

a2="$2"

awk -va1="$a1" -va2="$a2" '

BEGIN{

m= split(a1, A1," ")

n= split(a2, t," ")

for(i=1;i<=n;i++) { A2[t[i]] }

for (i=1;i<=m;i++){

if( ! (A1[i] in A2) ){

printf A1[i]" "

}

}

}'

}

Array4=( $(diff "$a1" "$a2") ) #compare a1 against a2

echo "Array4: ${Array4[@]}"

Array4=( $(diff "$a3" "$a1") ) #compare a3 against a1

echo "Array4: ${Array4[@]}"

输出

$ ./shell.sh

Array4: key7 key8 key9 key10

Array4: key11

ghostdog74 answered 2020-06-23T08:29:36Z

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值