Bashの2つのリストの交差


162

2つのリストにあるコンテンツを一覧表示する簡単なスクリプトを記述しようとしています。簡単にするために、例としてlsを使用します。「1」と「2」がディレクトリであると想像してください。

one = `ls one`
two = `ls two`
交差点$ one $ two

私はまだbashでかなり環境に優しいので、私がこれをどのように行っているかを自由に修正してください。「1つ」と「2つ」のすべてのファイルを出力するコマンドが必要です。それらは両方に存在する必要があります。これを「1つ」と「2つ」の「交差点」と呼ぶかもしれません。


ここでは実際に質問に答えるものはありません:Bashスクリプトで2つの変数を交差させる方法。
jameshfisher 2014

私の意見では新しい質問のようですが、その質問はここで明確に回答されています。
Jean-Christophe Meil​​laud 2014

間違いなくより多くの有用なアプローチは、近重複しているstackoverflow.com/questions/2312762/...
tripleee

回答:


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

37
comm今日まで知らなかったなんて信じられない。これでちょうど私の1週間が
終わりました

22
comm入力をソートする必要があります。この場合、ls自動的にその出力をソートしますが、他の用途には、これを実行する必要があるかもしれません:comm -12 <(some-command | sort) <(some-other-command | sort)
アレクサンダー・バード

11
lsの出力は何にも使用しないでください。lsは、インタラクティブにディレクトリメタデータを調べるためのツールです。コードでlsの出力を解析する試みはすべて失敗します。Globの方がはるかに単純で正しい: '' for file in * .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でいくつかのクレイジーなことをしようとしていました。
ロルフ

54

ソリューション comm

comm素晴らしいですが、確かにソートされたリストを操作する必要があります。幸い、ここlsではlsBashのmanページのどれを使用するか

-cftuSUXも--sortもない場合は、エントリをアルファベット順にソートします。

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

代替 sort

2つのリストの交差:

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

2つのリストの対称差:

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 2016年

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

3

(commより)効率が低い代替手段:

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

1
スクリプトでDebianの/ bin / dashまたはその他の非Bashシェルを使用している場合は、括弧を使用してコマンドの出力をチェーンできます(ls 1; ls 2) | sort -u | uniq -d
窒素

1
@MikaëlMayer返信する相手の名前にフラグを付ける必要があります。それ以外の場合は、私を意味していると見なされます。
Benubird、2015

@nitrogenMikaëlMayerは正解です。uniqがsort -u | uniq -d重複を探し始める前にソートが重複を削除したため、連鎖は何もしません。私の命令が何をしているか理解していないと思います。
Benubird、2015

@Benubird私もあなたのコマンドcat <(ls 1 | sort -u) <(ls 2 | sort -u) | uniq -dに何かを出力させることができませんでした。私のコマンドは(ls 1; ls 2) | sort | uniq -d-uリストの交差を表示するために、なしでを読む必要があります。@MikaëlMayerは私の元のコマンドが壊れていたのは正しかった。
窒素

@nitrogen私が猫を使用している理由は、これを一般化可能な解決策にして、ls他の何かで置き換えることができるようにしたいからですfind。コマンドの1つが同じ2行を返す場合、それは重複としてピックアップするため、ソリューションではこれを許可しません。ユーザーがls 1/*サブディレクトリ全体ですべてのファイルを実行して比較したい場合でも、Mineは機能します。そうでなければ、はい、それは同様に動作します。私の可能性はbash固有のものです。
Benubird 2015

2

結合は、入力と目的の出力に応じて別の良いオプションです

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

-1

Stackoverflowの別の質問「bashでの配列の交差」があり、これはこれの複製としてマークされています。私の意見では、この質問は2つのbash配列の比較について話しているため、まったく同じではありませんが、この質問はbashファイルに焦点を当てています。もう1つの質問への1行の回答は次のとおりです。

# 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」の使用法です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.