Bash中两个列表的交集


162

我正在尝试编写一个简单的脚本,该脚本将列出在两个列表中找到的内容。为了简化,让我们以ls为例。想象一下“一个”和“两个”是目录。

一=`一
两个=“ ls两个”
交叉点$ one $ two

我仍然很生气,所以随时可以纠正我的操作方式。我只需要一些命令即可打印出“一个”和“两个”中的所有文件。它们必须同时存在。您可以将其称为“一个”和“两个”之间的“交集”。


实际上,这里没有任何内容可以回答这个问题:如何在Bash脚本中将两个变量相交。
jameshfisher 2014年

在我看来,这似乎是一个新问题,在此明确回答了该问题。
Jean-Christophe Meil​​laud 2014年

可以说是一种更有效的途径是在近重复stackoverflow.com/questions/2312762/...
tripleee

Answers:


284
comm -12  <(ls 1) <(ls 2)

37
comm直到今天我都不知道。这让我整整一周都

22
comm需要对输入进行排序。在这种情况下,会ls自动对输出进行排序,但是可能需要其他用途:comm -12 <(some-command | sort) <(some-other-command | sort)
Alexander Bird

11
不要将ls的输出用于任何东西。ls是用于交互式查看目录元数据的工具。尝试用代码解析ls的输出的任何尝试都将失败。球更简单,更正确:“用于* .txt中的文件”。阅读mywiki.wooledge.org/ParsingLs
Rany Albeg Wein

2
我只是用它来尝试结合使用特质提供的public方法的用法,真是太棒了!我运行了,幸运的是我最后只得到了包含特征的文件名。error()git grep$ comm -12 <(git grep -il "\$this->error(" -- "*.php") <(git grep -il "Dash_Api_Json_Response" -- "*.php")
localheinz

3
这真可笑。我试图用awk做一些疯狂的事情。
罗夫(Rolf)

54

解决方案 comm

comm很棒,但确实需要使用排序列表。幸运的是,我们lslsBash手册页中使用了

如果-cftuSUX或--sort都没有,则按字母顺序对条目进行排序。

comm -12  <(ls one) <(ls two)

替代 sort

两个列表的交集:

sort <(ls one) <(ls two) | uniq -d

两个列表的对称差:

sort <(ls one) <(ls two) | uniq -u

奖金

玩;)

cd $(mktemp -d) && mkdir {one,two} && touch {one,two}/file_{1,2}{0..9} && touch two/file_3{0..9}

2
我认为这不是互补,而是通常所说的对称差
Andrew Lazarus

29

使用comm命令:

ls one | sort > /tmp/one_list
ls two | sort > /tmp/two_list
comm -12 /tmp/one_list /tmp/two_list

并不是真正需要“ sort”,但是为了以防万一,我总是在使用“ comm”之前将其包括在内。


5
包括它很好,因为它确实需要排序,并且他仅以ls为例。
Thor84no 2012年

3

效率比通讯低的替代方法:

cat <(ls 1 | sort -u) <(ls 2 | sort -u) | uniq -d

1
如果您在脚本中使用Debian的/ bin / dash或其他非Bash Shell,则可以使用括号将命令的输出链接起来:(ls 1; ls 2) | sort -u | uniq -d
氮气

1
@MikaëlMayer您应该标记您要回复的人的名字,否则假设您是我的意思。
Benubird

@nitrogenMikaëlMayer是正确的-链接sort -u | uniq -d没有任何作用,因为排序已在uniq开始寻找重复项之前将其删除。我认为您不了解我的命令在做什么。
Benubird

@Benubird我也无法使您的命令cat <(ls 1 | sort -u) <(ls 2 | sort -u) | uniq -d输出任何内容。我的命令应显示为(ls 1; ls 2) | sort | uniq -d,而不显示-u,以显示列表交集。@MikaëlMayer是对的,因为我原来的命令被破坏了。
氮气

@nitrogen之所以使用cat,是因为我希望它是一个可推广的解决方案,以便您可以ls用其他东西代替,例如find。您的解决方案不允许这样做,因为如果其中一个命令返回相同的两行,它将把它当作重复行。即使用户想要执行ls 1/*并比较子目录中的所有文件,Mine也能正常工作。否则,可以。我的可能是针对bash的。
Benubird

2

联接是另一个不错的选择,具体取决于输入和所需的输出

join -j1 -a1 <(ls 1) <(ls 2)

-1

还有另一个Stackoverflow问题“ bash中的数组交集”,被标记为与此重复。在我看来,这是关于比较两个bash数组的问题,而这个问题只针对bash文件。现在关闭了对另一个问题的单行回答:

# List1=( 0 1 2 3 4   6 7 8 9 10 11 12)
# List2=(   1 2 3   5 6   8 9    11 )
# List3=($(comm -12 <(echo ${List1[*]}| tr " " "\n"| sort) <(echo ${List2[*]} | tr " " "\n"| sort)| sort -g))
# echo ${List3[*]}
1 2 3 6 8 9 11

comm实用程序执行字母数字排序,而“ bash中的数组交集”则使用数字进行回答。因此使用“ sort”和“ sort -g”。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.