• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:2つのファイルのレコードの差異を抽出したいのです。)

2つのファイルのレコードの差異を抽出する方法は?

このQ&Aのポイント
  • ファイルAとファイルBのレコードの差異を抽出する方法を考えています。ファイルAとファイルBのレコードを比較し、同じid(一番左の値)で更新日付と更新者以外が更新されていた場合はファイルCに書き出すようにしたいと考えています。現在はファイルAのレコードを1行ずつ読み出し、ファイルBと比較して差異を検出していますが、より良い方法があるかどうかアドバイスをいただきたいです。
  • ファイルAとファイルBのレコードの差異を抽出する方法を教えてください。ファイルAとファイルBは順不同のレコードを持っており、同じid(一番左の値)で更新日付と更新者以外が異なる場合に差異とみなしたいです。現在はファイルAを1行ずつ読み出してファイルBと比較し、差異があればファイルCに書き出していますが、もっと効率的な方法があるかどうか教えてください。
  • ファイルAとファイルBのレコードの差異を抽出する方法を教えてください。ファイルAとファイルBは数十万件以上のレコードを持っており、同じidで更新日付以外の項目が異なる場合に差異とみなしたいです。現在はファイルAを1行ずつ読み出し、ファイルBと比較して差異を検出していますが、より高速な方法があるかどうか教えてください。

質問者が選んだベストアンサー

  • ベストアンサー
  • notnot
  • ベストアンサー率47% (4900/10358)
回答No.3

>分からなかったのはAにしかない行があるならawkに追加処理が必要とありますが、片方にしか存在しない行は片方が@になるので、このままでもうまく差分が出るかと思うのですが、 キーidがAにあって、Bにない場合、 id000,日本太郎,30才,東京都,2010/04/06,batch,@,@,@,@,@,@ のようになりますが、#1に書いたawkコマンドだとそれを考慮してません。 テストしてませんが、こんな感じかな。 awk -F, -v OFS=, '$2!=$8 || $3!=$9 || $4!=$10 {if($1=="@"){print $7,$8,$9,$10,$11,$12 }else{print $1,$2,$3,$4,$5,$6}}' >また固定長のファイルの場合は、awkで同じような処理ができるのでしょうか? gnu-awk (Linuxのawkだとこれ) だと、 >FIELDWIDTHS > 空白で区切られたフィールド長のリスト。もしこの値が設定されていれば、 >gawk は FS の値を用いてフィールド分割するかわりに、固定長のフィールド分割を行います。 という機能がありますので、例えば awk -v FIELDWIDTHS="2 4 1 3 10" '{print $1,$4}'

_alias_
質問者

お礼

お返事遅れてごめんなさい。 アクションのprintの方を見ていませんでした。なるほど理解できました。 FIELDWIDTHSというのは便利そうですね。自分の環境で使えるか確認してみたいと思います。 ありがとうございました。

その他の回答 (2)

  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.2

シェルスクリプトだけでもできないことは無いだろうけど、PerlやRubyやPythonといったスクリプトを使ったほうが楽にできそうです。 例えばPerlでこんな風に。 #!/opt/local/bin/perl open FPA, "afile.csv"; %a=(); while (<FPA>) { @s=split(/,/); #,で分解 $a{$s[0]}=\@s ; # idをキーにしてリストを代入 } close FPA ; open FPB, "bfile.csv"; while (<FPB>) { @t=split(/,/); #,で分解 if ( ! defined ($a{$t[0]}) ) { #Aにidがない print ; } else { $s = $a{$t[0]} ; $p = 0 ; for ( $i = 1 ; $i < $#t ; $i ++ ) { if ( $i == 4 ) { next ; } # $t[4]は更新日付なので比較しない if ( $t[$i] ne $s->[$i] ) { $p=1; break ; } # 違う箇所があった } if ($p != 0 ) { print ; } #違う箇所があったらprint } } close FPB ; エラー処理とか、strictとか、重複した場合とかはまったく考えていないです。

_alias_
質問者

お礼

お返事おくれてごめんなさい。 なるほど、perlですか。こちらも実際に打ち込んでみて挙動を色々と勉強させて頂きました。昔CGIで掲示板をHPに設置する際にperlを勉強しようと思ったのですが、なかなかうまくいかずに苦手意識を持っていました。 perlが分かると色々便利ですよね。この機会にもう一度チャレンジしてみたいと思います。 ※なぜ苦手なのだろうと理由が分からないのですが、$なんちゃらの記号が何を意味しているのかとか、省略可能なものがあるとかなのかな~と考えています。

  • notnot
  • ベストアンサー率47% (4900/10358)
回答No.1

お書きの方法だと、Aの行数回だけBを読む必要があるので遅いですよね。 idでソートされているという前提であれば、joinコマンドで同じidの両方の行をつなげられますので、つないだものをカンマで区切って処理すれば無駄にファイルを読むことなく処理できます。 join -t, -a 1 -a 2 -o 1.1 1.2 1.3 1.4 1.5 1.6 2.1 2.2 2.3 2.4 2.5 2.6 -e @ A B 出力はこうなるので、 @,@,@,@,@,@,id000,日本太郎,30才,東京都,2010/04/06,batch id001,日本次郎,25才,東京都,2010/04/06,batch,id001,日本次郎,28才,東京都,2010/04/08,batch id002,日本花子,20才,千葉県,2010/04/06,batch,id002,日本花子,20才,千葉県,2010/04/08,batch あとは、awkで処理。 awk -F, -v OFS=, '$2!=$8 || $3!=$9 || $4!=$10 {print $7,$8,$9,$10,$11,$12}' A にしかない行があるならawkにもうちょっと処理の追加が必要です。

_alias_
質問者

お礼

お返事おくれてごめんなさい。教えて頂いたスクリプトを実際に試して意図通りの動きになりました。ただオプション等が何をしているのか分からなかったので調べてたりしました。 分からなかったのはAにしかない行があるならawkに追加処理が必要とありますが、片方にしか存在しない行は片方が@になるので、このままでもうまく差分が出るかと思うのですが、これは片方しか存在しない場合は差分なしと見る場合はという認識でよいでしょうか? また固定長のファイルの場合は、awkで同じような処理ができるのでしょうか? awkはなんらかの区切り文字でフィールドを分断するので、固定長で各項目が何文字とか決まっているような行に対してはそのままだと出来ないような気がするのですが、何かよい手はありますでしょうか。

関連するQ&A