hogehoge foobar Blog Style Beta

Web,Mac,Linux,JavaScript,Perl,PHP,RegExp,Git,Vim,Redmineなど技術的なことのメモや、ちょっと便利そうなものの紹介をしています。

diff + grep + perlで相違点(差分)だけを抽出する

csvファイルやtsvファイルでデータ作成をする場合、過去に作ったファイルと新しいファイルとの差分だけを抽出したファイルを作成したいことがあります。
※私の場合、DBに登録するデータをtsvで相手先に2回に分けて送る必要があり、2回目は差分だけのデータを送らなければならないことがありました。

通常のdiffコマンドだけだと出来ないので、grep(egrep)とperlを使って実現してみました。

差分を抽出するデータ(サンプル)

では、以下のfoo.csvとbar.csvを対象にして差分を抽出してみます。
ファイルの中身は以下になります。(csvファイル)





foo.csv

01 りんご
02 みかん
03 すいか


bar.csv

02 みかん
03 めろん
04 ぶどう

このfoo.csvとbar.csvを普通にdiffで比較してみると差分を確認します。
foo.csvの相違点には行の先頭に「<」が表示されます。
逆のbar.csvの相違点には行の先頭に「>」が表示されます。

diff foo.csv bar.csvの実行結果
$ diff foo.csv bar.csv
1d0
< "01","りんご"
3c2,3
< "03","すいか"
---
> "03","めろん"
> "04","ぶどう"

差分を抽出するコマンド(diff + grep + perl)

上記の「diff foo.csv bar.csvの実行結果」を元に差分だけを抽出したファイルを作成します。
処理の順番としては、

  1. diffでファイルを比較
  2. grep(egrep)で相違点(先頭に"<"または">")の行のみを抽出
  3. 2.で抽出した行の先頭の「< 」(または「> 」)を削除
  4. 3.の実行結果をファイルに出力(リダイレクト)

といった流れになります。
処理の順番をつらつらを書きましたが、実際にはdiff + grep + perlをパイプで繋ぎリダイレクトでファイルに出力するので、事実上コマンド一発で行います。

grep -E」と「egrep」はどちらを使用しても結果は変わりません。
コマンドの見た目的には「egrep」を使用したほうがスッキリするかなとは思います。

foo.csvの相違点のみを抽出
  • grep -E」で行う場合
diff foo.csv bar.csv | grep -E '^<' | perl -pe 's/^<\s//g' > diff_left.csv
  • 「egrep」で行う場合
diff foo.csv bar.csv | egrep '^<' | perl -pe 's/^<\s//g' > diff_left.csv
  • 実行後に作成されたファイル(diff_left.csv)
01 りんご
03 すいか
bar.csvの相違点のみを抽出
  • grep -E」で行う場合
diff foo.csv bar.csv | grep -E '^>' | perl -pe 's/^>\s//g' > diff_right.csv
  • 「egrep」で行う場合
diff foo.csv bar.csv | egrep '^>' | perl -pe 's/^>\s//g' > diff_right.csv
  • 実行後に作成されたファイル(diff_right.csv)
03 めろん
04 ぶどう

実際にこのコマンドを使用するケースはあまり多く無いと思いますが、覚えておくとラクな場合があると思います。

今回参考にしたページ

Perl第4回:PerlTips(コマンドラインオプション)
http://www.stackasterisk.jp/tech/program/perl04_04.jsp

UNIXの部屋 コマンド検索: grep
http://x68000.q-e-d.net/~68user/unix/pickup?grep

UNIXの部屋 コマンド検索: diff
http://x68000.q-e-d.net/~68user/unix/pickup?diff

024.diffコマンド ファイルの相違点を抽出する:Linuxコマンド.com
http://xn--linux-op4dtfrgoh.com/01linux/024diff.html