ソート済みファイル同士を比較したい

2つのソート済みファイルを比較して、どちらか片方にだけ存在する行や、両方に共通する行を抽出したい。

例えば以下のような2つのファイルがある。

apple
banana
cherry
grape
banana
cherry
melon
orange

2つのファイルを比較して、以下の情報を得たい。

  • file1にだけある行: apple, grape
  • file2にだけある行: melon, orange
  • 両方に共通する行: banana, cherry

comm コマンド

commコマンドは2つのソート済みファイルを行単位で比較するコマンド。

$ comm file1.txt file2.txt
apple
		banana
		cherry
grape
	melon
	orange

commコマンドは3列で出力する。

  • 1列目(インデントなし): file1にだけある行
  • 2列目(タブ1つ): file2にだけある行
  • 3列目(タブ2つ): 両方に共通する行

上記の出力では、appleとgrapeが1列目、melonとorangeが2列目、bananaとcherryが3列目に表示される。

file1にだけある行を表示する

-2-3オプションで2列目と3列目を非表示にすると、file1にだけある行を抽出できる。

$ comm -23 file1.txt file2.txt
apple
grape

file1にだけ存在する行が出力される。

file2にだけある行を表示する

-1-3オプションで1列目と3列目を非表示にすると、file2にだけある行を抽出できる。

$ comm -13 file1.txt file2.txt
melon
orange

file2にだけ存在する行が出力される。

両方に共通する行を表示する

-1-2オプションで1列目と2列目を非表示にすると、両方に共通する行を抽出できる。

$ comm -12 file1.txt file2.txt
banana
cherry

両方のファイルに共通する行が出力される。

ファイルは事前にソートが必要

commコマンドはソート済みファイルを前提とする。ソートされていないファイルを指定すると正しい結果が得られない。

cherry
apple
banana
banana
orange
cherry
$ comm -12 unsorted1.txt unsorted2.txt
comm: file 1 is not in sorted order
comm: file 2 is not in sorted order
comm: input is not in sorted order

ソートされていないため、エラーメッセージが表示される。

事前にsortコマンドでソートするか、プロセス置換を使用する。

$ comm -12 <(sort unsorted1.txt) <(sort unsorted2.txt)
banana
cherry

プロセス置換<(command)を使用すると、コマンドの出力を一時ファイルとして扱える。

参考:コマンド結果をdiffコマンドで比較する

具体例

2つのユーザーリストの差分を確認する

サーバー間でユーザーリストの差分を確認する場合にcommコマンドが便利。

$ cut -d: -f1 /etc/passwd | sort > users1.txt
$ ssh server2 "cut -d: -f1 /etc/passwd" | sort > users2.txt
$ comm -3 users1.txt users2.txt

-3オプションで共通部分を非表示にすると、どちらかのサーバーにしか存在しないユーザーを確認できる。

今日追加されたファイルを確認する

昨日のファイルリストと今日のファイルリストを比較して、新しく追加されたファイルを確認する。

$ ls /var/www/html | sort > yesterday.txt
# (1日後)
$ ls /var/www/html | sort > today.txt
$ comm -13 yesterday.txt today.txt

-13オプションでtoday.txtにだけ存在する行(今日追加されたファイル)を抽出できる。

パッケージの差分を確認する

2つのサーバーで異なるパッケージがインストールされているか確認する。

$ rpm -qa | sort > server1_packages.txt
$ ssh server2 "rpm -qa | sort" > server2_packages.txt
$ comm -3 server1_packages.txt server2_packages.txt

サーバー間のパッケージの差分を確認できる。

git管理対象のファイルと実際のファイルを比較する

gitで管理されているファイルと、実際のディレクトリ内のファイルを比較する。

$ git ls-files | sort > git_files.txt
$ find . -type f | sed 's|^\./||' | sort > actual_files.txt
$ comm -13 git_files.txt actual_files.txt

実際のディレクトリに存在するが、gitで管理されていないファイルを抽出できる。