如何比较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
我也在寻找其他的解决方案。
如何比较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
我也在寻找其他的解决方案。
将列表1的元素用作在列表2中查找的正则表达式(表示为字符串:${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
采用@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?)
输出
foo bar`(分两行)。在你的系统上不是这样吗? - ruakhprintf -- '%s\n' "${array[@]}"
将输出数组中的每个元素,每个元素占一行。 - Noel Yap$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
result=$result" "$item1
不会按照你想象的那样运行,除非你已经将 IFS
变量设置为某些奇怪的值,但我真的很怀疑你这样做了。 (如果你确实将 IFS
变量设置为某些奇怪的值,那么你就有不同的问题!) - ruakhresult=$result" "$item1
似乎可以正常工作,即使我没有设置IFS为任何值。我将保留问题不变,因为这仍将帮助其他人解决数组比较问题。 - dabest1result=$result
$item1
似乎工作得很好”的问题:糟糕,我的错误:事实证明(根据http://www.gnu.org/s/bash/manual/bash.html#Shell-Parameters),变量赋值时不执行单词拆分。我错了。 - ruakh如果您要查找相交线路的两个文件(而不是数组),则可以使用comm
命令。
$ comm -12 file1 file2
现在我理解了你所说的“数组”,首先,我认为你应该考虑使用实际的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
中的第一个数组的元素。
这将与您的代码在如何处理第二个数组中的重复值方面略有不同;在您的代码中,如果array1
两次包含x
,而array2
包含x
三次,则result
将包含x
六次,而在我的代码中,result
将只包含x
两次。我不知道这是否重要,因为我不知道您的确切要求。