LoginSignup
2
2

More than 3 years have passed since last update.

shell script: 2つのcsvファイルを縦に並べ,集合演算を用いて差分を取り出す.

Last updated at Posted at 2020-04-18

はじめに

 2つのファイルの差分をとりたいことがある[1].代表的な方法にdiffgrepcommを用いた方法がある[2].他に,集合演算で差集合を求めることで差分を取り出せる[3].集合演算で行う場合,手順が増えるが,概念的に理解しやすいという利点もある.個人で扱う程度の小規模なデータであれば実用できると思われる.例えば,以前から収集していた保存データと,新たに集めたデータとの差分をとり,その差分をあらたに保存データに加える,といった利用方法が考えられる.収集するデータの保存形式としてテキストやcsv形式が考えられる.ここではデータ整理を意識してcsvファイルで行う.また,集合演算にはsortuniqを組み合わせる方法[3]とsortjoinを組み合わせる方法とがある[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.csvfile_2.csv
  • 1列目は収集したwebページのurl,2列目はtitleをいれる.
  • file_1.csvはwebページ5件分,すなわち5行.file_2.csvは10件分,すなわち10行.
  • 共通部分が2行分あるようにする.
file_1.csvの内容をcatで表示する.
cat file_1.csv
url_1,title_1
url_2,title_2
url_3,title_3
url_4,title_4
url_5,title_5
file_2.csvの内容をcatで表示する.
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を用いた盲目的連結方法
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

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2