-1

次の構造の2つのファイル(new.txtとold.txt)を比較する必要があります。

 <Field1>,<Field2>,<Field3>,<Field4>,<Field5>,<Field6> 
  1. 共通行はスキップする必要があります。
  2. new.txtとold.txtの同様の行をグループ化する必要があります。Field1、Field2、Field3、Field4が同じ場合、old.txtの行はnew.txtの行と似ていると思います。
  3. 他の一意の行は、ファイル名でグループ化して以下に印刷する必要があります

したがって、最終的なタスクは、視覚的な比較を容易にすることです。

追加された部分: 例。

$ cat old.txt 
 one,two,three,four,five,six
 un,deux,trois,quatre,cinq,six
 eins, zwei, drei, vier, fünf, sechs
$ cat new.txt 
 one,two,three,four,FIVE,SIX
 un,deux,trois,quatre,cinq,six
 en,två,tre,fyra,fem,sex

$cat comparison_result:
# lines are grouped. So it it easy to find the difference without scrolling.
old.txt> one,two,three,four,five,six
new.txt> one,two,three,four,FIVE,SIX
# end of task 2. There are no more simillar lines.
#
#start task 3.
#Printing all the rest unique lines of old.txt 
echo "the rest unique line in old.txt"
eins, zwei, drei, vier, fünf, sechs
.... 
#Printing all the rest unique lines of new.txt
echo "the rest unique line in new.txt"
en,två,tre,fyra,fem,sex

これはステップ1である可能性があります:一般的な行をスキップします。

 # This is only in old.txt
 comm -2 -3 <(sort old.txt) <(sort new.txt) > uniq_old

 # This is only in new.txt
 comm -1 -3 <(sort old.txt) <(sort new.txt) > uniq_new

ステップ1を作成し、このソートされた差分を一時的な解決策として作成しました。

 # additional sort improves a bit diffs results.
 diff <(sort uniq_old) <(sort uniq_new)

動作していますが、理想的ではありません。ブロックの比較を開始し、共通行が欠落しているため、diffの使用を拒否しました。

上記の3つの要求を満たすためのより良い方法はありますか?

私はそれができると思います

  1. このsort、diff、commコマンドのいくつかの改善(最後の2つのファイルを一時的に「非表示」にするためにsed / trを追加し、残りを比較します)。
  2. awk

私はawkがそれをより良くすることができると思いますか?

4

1 に答える 1

1

これはどうですか?

awk -F, 'NR==FNR{old[$0];next} $0 in old{delete old[$0];next} 1 END{for(line in old) print line}' old.txt <(sort -u new.txt) | sort

それをいくつかの部分に分解しましょう。

  • -F,,aをフィールド区切り文字として使用するようにawkに指示します。
  • NR==FNR{old[$0];next}-NR(レコード/行番号)が現在のファイルの行番号と一致する場合(つまり、最初の入力ファイルを読み取っている場合)、行全体を連想配列のインデックスとして格納してから、にジャンプします。次のレコード。
  • $0 in old{delete old[$0];next}--2番目のファイルを読み取っています。現在の行が配列内にある場合は、配列からifを削除して、次に進みます。あなたの質問のこのアドレス条件#1。
  • 1-「行を印刷する」ためのawkの速記。これは、2番目のファイルから一意の行を印刷することにより、質問の条件#3の一部に対処します。
  • END{...}-このループは、配列から削除されなかったものをすべて出力します。これは、最初のファイルから一意の行を出力することにより、条件#3の他の部分に対処します。
  • <(sort -u new.txt)--new.txtの入力を一意にします。new.txtがすでに一意であることがわかっている場合は、このbashの依存関係を削除できます。
  • | sort出力を並べ替え、質問の条件#2ごとに物事を「グループ化」します。

サンプル出力:

 $ cat old.txt 
 one,two,three,four,five,six
 un,deux,trois,quatre,cinq,six
 $ cat new.txt 
 one,two,three,four,FIVE,SIX
 un,deux,trois,quatre,cinq,six
 en,två,tre,fyra,fem,sex
 $ awk -F, 'NR==FNR{old[$0];next} $0 in old{delete old[$0];next} 1 END{for(line in old) print line}' old.txt new.txt | sort
 en,två,tre,fyra,fem,sex
 one,two,three,four,FIVE,SIX
 one,two,three,four,five,six
 $ 

フランス語の行が重複しているため、削除されていることに注意してください。それ以外はすべて印刷され、2つの英語の行が並べ替えによって「グループ化」されました。

また、old.txtはすべて配列としてメモリに読み込まれるため、このソリューションは非常に大きなファイルで問題が発生することにも注意してください。あなたのために働くかもしれない代替案はこれでしょう:

 $ sort old.txt new.txt | awk '$0==last{last="";next} last{print last} {last=$0} END{print last}' | sort
 en,tva,tre,fyra,fem,sex
 one,two,three,four,FIVE,SIX
 one,two,three,four,five,six
 $ 

ここでの考え方は、ファイルからすべての入力データを取得して並べ替え、awkスクリプトを使用して繰り返し行をスキップし、その他すべてを出力するだけです。次に、出力を並べ替えます。これは、awkに関する限り、ストリームで機能しますが、入力が非常に大きい場合sortでも、コマンドでデータをメモリや一時ファイルにロードする必要があることに注意してください。

また、現状では、特定の行が複数回繰り返されると、この2番目の解決策は失敗します。つまり、old.txtに1回、new.txtに2回存在する場合です。入力ファイルを一意にするか、その状況に合わせてスクリプトを適合させる必要があります。

于 2013-02-07T18:46:29.240 に答える