はじめに
2つのファイルの差分をとりたいことがある[1].代表的な方法にdiff
,grep
,comm
を用いた方法がある[2].他に,集合演算で差集合を求めることで差分を取り出せる[3].集合演算で行う場合,手順が増えるが,概念的に理解しやすいという利点もある.個人で扱う程度の小規模なデータであれば実用できると思われる.例えば,以前から収集していた保存データと,新たに集めたデータとの差分をとり,その差分をあらたに保存データに加える,といった利用方法が考えられる.収集するデータの保存形式としてテキストやcsv形式が考えられる.ここではデータ整理を意識してcsvファイルで行う.また,集合演算にはsort
とuniq
を組み合わせる方法[3]とsort
とjoin
を組み合わせる方法とがある[8].ここでは前者を用いる.
環境
MacOS: 10.15.3
zsh: 5.7.1
準備
CSV形式について.
csv形式はテキストエディタで編集できる,またExelやNumbersといった様々な表計算ソフトで扱える.すなわち,様々な環境で扱えるのがcsv形式の利点である[4],一方,csvの書き方には様々な"方言"があり,よく定義されているといは言い難く,それが原因で不都合を生ずることがある[5][6].あらゆる状況に対応できるようにするのはかなり大変である.そこで,ここでは個人利用を想定し,自分なりの書き方を決めておくことにして,なるべく簡素に書くことにする.うまくいかない場合は置換など用いて適宜対応することにする.例えば以下の様にする.
- 要素をあえてダブルクオートで挟まない.
- 区切りはカンマ
,
とする. - 改行はあえて'\n'のみを扱う.
- など
要素について
- 1行を1つの要素として扱う.
練習用のファイルを2つ準備
- 練習用に2つのcsvファイルを準備する
file_1.csv
,file_2.csv
. - 1列目は収集したwebページのurl,2列目はtitleをいれる.
- file_1.csvはwebページ5件分,すなわち5行.file_2.csvは10件分,すなわち10行.
- 共通部分が2行分あるようにする.
cat file_1.csv
url_1,title_1
url_2,title_2
url_3,title_3
url_4,title_4
url_5,title_5
cat file_1.csv
url_1,title_4
url_2,title_5
url_3,title_6
url_4,title_7
url_5,title_8
url_5,title_9
url_5,title_10
url_5,title_11
url_5,title_12
url_5,title_13
2つのファイルを縦に並べる.
- ここが一番重要なところである.
- 過去の記事を参考にし,ファイルを縦に並べて集合演算を行う.
- 最終行末尾の改行の有無を気にせず2つのファイルを連結したいときは以下の
awk
を用いれば,盲目的に操作でき,簡潔[7].
awk 1 'file_1.csv' 'file_2.csv'
集合演算概要
- 2つのファイルを縦に並べる.
-
sort
で順に並べる. -
uniq
で重複して数えない様にする(和集合). -
uniq -d
では重複すると行が数えられる(積集合). -
uniq -u
では重複しないところだけ数えられる(排他的和集合). - 和集合とfile_1を縦に並べ,
sort
で並べ替え,重ならないところを数える(差集合).
和集合(union, A OR B)
- 13行分が表示される.
awk 1 'file_1.csv' 'file_2.csv' | sort | uniq
積集合(intersection, A AND B)
- 2行分が表示される.
awk 1 'file_1.csv' 'file_2.csv' | sort | uniq -d
排他的論理和(exclusive union, A XOR B)
- 11行分が表示される.
awk 1 'file_1.csv' 'file_2.csv' | sort | uniq -u
差集合(difference set, A - B)
- 和集合とfile_2.csvとを重ね,重ならないところを取り出す.
- 2つ目のawkは左から和集合を受け,右からfile_2.csvを受ける.
- パイプではなくセミコロン
;
にする.かっこ()
で挟む[3].
(awk 1 file_1.csv file_2.csv | uniq \
; awk 1 file_2.csv) \
| sort \
| uniq -u
差集合(difference set, B - A)
(awk 1 file_1.csv file_2.csv | uniq \
; cat file_1.csv) \
| sort \
| uniq -u
結果,考察
- リダイレクトを用いれば,差分を元のファイルに追加できる.
まとめ
- 集合演算を用いて2つのcsvファイルの差分をとりだす方法を述べた.
参考
[1]https://superuser.com/questions/234810/how-do-i-compare-two-files-with-a-shell-script
bash - How do I compare two files with a shell script? - Super User
[2]https://qiita.com/mekagazira/items/1a1791a42e435cefd5f6
2つのファイルの共通行を抽出する方法 - Qiita
[3]https://kunst1080.hatenablog.com/entry/2015/01/25/011158
uniqコマンドを使って、論理和・論理積・排他的論理和・差集合を得る方法 - くんすとの備忘録
[4]https://shikaku.wakarutodekiru.com/blog/mame/2933.html
CSVファイルとは何?何のために使うの?
[5]https://codezine.jp/article/detail/2364
CSVファイルフォーマットの解説:CodeZine(コードジン)
[6]https://postd.cc/so-you-want-to-write-your-own-csv-code/
それでも独自のCSVを書くつもりですか? | POSTD
[7]https://qiita.com/BlackCat_617/items/f587af94fca62a23f0dc
ShellScript: 2つのテキストファイルを縦に連結する. - Qiita
[8]https://qiita.com/highfrontier/items/610cd285f0c0de480ac9
コマンドラインで集合演算 - Qiita