bash中的数组交集

时间:2011-10-24 00:07:33

标签: bash

如何比较bash中的两个数组以查找所有相交的值?

让我们说:
array1包含值1和2
array2包含值2和3

我应该回来2。

我自己的答案,由于声誉不佳,我无法发帖:

for item1 in $array1; do
    for item2 in $array2; do
        if [[ $item1 = $item2 ]]; then
            result=$result" "$item1
        fi
    done
done

我也在寻找替代解决方案。

5 个答案:

答案 0 :(得分:17)

列表1的元素用作在list2中查找的正则表达式(表示为字符串:$ {list2 [*]}):

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[@]}

结果是

1 2 3 6 8 9 11

答案 1 :(得分:8)

采用@Raihan的答案并使其与非文件一起使用(虽然创建了FD) 我知道这有点像作弊,但似乎是不错的选择

副作用是输出数组将按字典顺序排序,希望没关系 (也不知道你有什么类型的数据,所以我只是用数字测试,如果你有特殊字符的字符串等可能需要额外的工作)

result=($(comm -12 <(for X in "${array1[@]}"; do echo "${X}"; done|sort)  <(for X in "${array2[@]}"; do echo "${X}"; done|sort)))

测试:

$ array1=(1 17 33 99 109)
$ array2=(1 2 17 31 98 109)

result=($(comm -12 <(for X in "${array1[@]}"; do echo "${X}"; done|sort)  <(for X in "${array2[@]}"; do echo "${X}"; done|sort)))

$ echo ${result[@]}
1 109 17

P.S。我确定有一种方法可以让数组在for循环中每行输出一个值,我只是忘了它(IFS?)

答案 2 :(得分:3)

如果是两个文件(而不是数组),你正在寻找相交的行,你可以使用comm命令。

$ comm -12 file1 file2

答案 3 :(得分:2)

您的回答无效,原因有两个:

  • $array1只是扩展为array1的第一个元素。 (至少,在我安装的Bash版本中,它是如何工作的。这似乎不是一个记录在案的行为,所以它可能是一个依赖于版本的怪癖。)
  • 第一个元素添加到result后,result将包含一个空格,因此result=$result" "$item1的下一次运行会出现可怕的错误行为。 (而不是附加到result,它将运行由前两项组成的命令,并将环境变量result设置为空字符串。)更正:转动我错了这个:在分配中不会发生分词。 (见下面的评论。)

你想要的是这个:

result=()
for item1 in "${array1[@]}"; do
    for item2 in "${array2[@]}"; do
        if [[ $item1 = $item2 ]]; then
            result+=("$item1")
        fi
    done
done

答案 4 :(得分:0)

现在我理解你对“数组”的意思了,我认为 - 首先 - 你应该考虑使用实际的Bash数组。它们更灵活,因为(例如)数组元素可以包含空格,并且可以避免*?触发文件名扩展的风险。

但是如果您更喜欢使用现有的以空格分隔的字符串方法,那么我同意RHT建议使用Perl:

result=$(perl -e 'my %array2 = map +($_ => 1), split /\s+/, $ARGV[1];
                  print join " ", grep $array2{$_}, split /\s+/, $ARGV[0]
                 ' "$array1" "$array2")

(换行符只是为了便于阅读;如果你愿意,你可以摆脱它们。)

在上面的Bash命令中,嵌入式Perl程序创建一个名为%array2的哈希,其中包含第二个数组的元素,然后它会打印%array2中存在的第一个数组的所有元素。 / p>

这与你在第二个数组中处理重复值的代码的行为略有不同;在您的代码中,如果array1包含x两次且array2包含x三次,则result将包含x六次,而在我的代码result只会包含x两次。我不知道这是否重要,因为我不知道你的具体要求。