Linuxコマンド
UNIXコマンド
消し込み

Linuxコマンドを使って行う「消し込み作業」

UNIX や Linux はテキスト処理が得意で、 grep や sort コマンドを組み合わせて便利に使えることはみなさんご存知で、便利ワンライナーやシェル芸づくりに勤しんでいるかと思います。

そんな中、あまり有名ではないけれども純粋な消し込み作業で威力を発揮するコマンドの使い方を学んだので書いてみます。


直面した課題

以下の2つのテキストファイルを比べて 001.txt にのみ含まれる行を出力してください。


001.txt

11111

22222
44444
77777
88888


002.txt

11111

22222
33333
55555
88888


直感的に考えてみる

なにも考えずに「テキストファイルの差分を調べる」と考え、diff コマンドを使うことが真っ先に思いつきますが、差分情報そのものは実は扱いづらかったりします。実際に実行してみると

$ diff 001.txt 002.txt

3,4c3,4
< 44444
< 77777
---
> 33333
> 55555

という出力を得ることができます。 < のある行をさらに切り出すというのも考えられますが、それはそれで面倒です。 -u でユニファイド形式で出力してもあまり事態は変化せず

$ diff -u 001.txt 002.txt 

--- 001.txt 2019-04-17 21:04:23.755129521 +0900
+++ 002.txt 2019-04-17 21:04:33.479021128 +0900
@@ -1,5 +1,5 @@
11111
22222
-44444
-77777
+33333
+55555
88888

という形で、ソースファイルの差分だったら見やすいけれども消し込みには使いづらい出力になってしまいます。


ソート済の2ファイルの差分を比較する comm コマンド

このような用途にマッチするのは、あまり知られてはいない comm コマンドです。入力ファイルを2つ引数に指定すると、このような出力が得られます。

$ comm 001.txt 002.txt

11111
22222
33333
44444
55555
77777
88888

環境によってみづらいかもしれないので、実際にコマンドを実行して確認して欲しいのですが行単位のファイル間の差分が3列で表示されます。それぞれの列の意味は


  • 1列目 : 1つめのファイルにのみ記述されている行

  • 2列目 : 2つめのファイルにのみ記述されている行

  • 3列目 : 双方のファイルに共通して記述されている行

となっています。ファイル間の差がわかりやすく表示されています。

そして comm コマンドには、それぞれの列の表示を省略するオプション -1 -2 -3 が準備されていています。今回の課題では「1つめのファイルにのみ記述されている行」が欲しいわけですから、2,3列目を省略するように

$ comm -2 -3 001.txt 002.txt 

44444
77777

とすることで目的の結果を得ることができます ( オプション指定は同時に -23 と指定してかまいません ) 。


注意点

このような comm コマンドですが、使用する際に注意する点があります。


  • 比較するファイルは事前にソートしておくこと

  • 目に見える部分だけでなく改行コードなども統一しておくこと

比較するファイルがソートされていない場合には、 comm コマンド実行時にソートされていない旨の警告が表示されるので気が付きやすいですが、改行コードや空白、タブは見落としやすいところです。しっかり前処理しておくことが大切です。


comm コマンドが使える環境

comm コマンドは GNU coreutils に含まれるコマンドです。多くの Linux システムで使用することができます。今回のような非常に小さいケースではコマンドを使わなくてもスプレッドシートアプリで処理することができますが、件数が多くなった場合にはお手上げになってしまうので、このような手法も覚えておくと便利です。