例えば、サービスAでは登録されているけれどもサービスBには登録されていないユーザの一覧を得たい、という様な場合。もちろんdiffでよしなにやることもできますが、commも便利です。

例えば次の様にリストがあるとします。

サービスAのユーザーリスト(users_a.txt):

1
2
3
4
5
alice
bob
charlie
dave
oscar

サービスBのユーザーリスト(users_b.txt):

1
2
3
4
5
charlie
isaac
justin
mallory
oscar

これらに対してcommを使うと次の出力が得られます:

1
2
3
4
5
6
7
8
9
$ comm users_a.txt users_b.txt
alice
bob
                charlie
dave
        isaac
        justin
        mallory
                oscar

TABで揃えられた列がそれぞれ左から、Aにだけ存在する行、Bにだけ存在する行、Cにだけ存在する行、となっています。これだけだと別にそれほど便利ではないんですが、commはそれぞれの行を非表示にする事もできます。それぞれ、非表示にしたい行を-1 -2 -3で指定します。

Aだけに存在する行を表示する:

1
2
3
4
$ comm -23 users_a.txt users_b.txt
alice
bob
dave

両方に存在する行を表示する:

1
2
3
$ comm -12 users_a.txt users_b.txt
charlie
oscar

diffだとdiffの後にgrepやらなんやらして必要な物を抜き出す必要があるでしょうから、これは楽ですね。

もちろん、diffの様に他のコマンドの標準出力を取ることもできます。

例えばhttps://example.com/api/users_b.txtが先ほどのusers_b.txtと同じ内容を返すとするとしてAだけに登録しているユーザーを取得したい場合

1
2
3
4
$ curl -s https://example.com/api | comm -23 users_a.txt -
alice
bob
dave

とできますし、2つのユーザーリストを返すAPIが有ったとして、共通のユーザーを一覧にしたい場合、次の様にできます:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
$ curl https://example1.com/users | jq .
[
  {
    "username": "alice"
  },
  {
    "username": "bob"
  },
  {
    "username": "charlie"
  },
  {
    "username": "dave"
  },
  {
    "username": "oscar"
  }
]
$ curl https://example2.com/users | jq .
[
  {
    "username": "charlie"
  },
  {
    "username": "isaac"
  },
  {
    "username": "justin"
  },
  {
    "username": "mallory"
  },
  {
    "username": "oscar"
  }
]
$ comm -12 \
  <(curl -s https://example1.com/users | jq -r '.[].username') \
  <(curl -s https://example2.com/users | jq -r '.[].username')
charlie
oscar

便利ですね。

なお、入力となるテキストはソートされている必要があることに注意が必要です。

以上です。