Linux awk يقارن بين ملفين بتنسيق CSV وينشئ ملفًا جديدًا بعلامة
-
15-11-2019 - |
سؤال
لدي ملفين CSV أحتاج إلى مقارنتهما والحصول على الفرق مع ملف منسق حديثًا.وترد العينات أدناه.
الملف القديم
DTL,11111111,1111111111111111,11111111111,Y,N,xx,xx
DTL,22222222,2222222222222222,22222222222,Y,Y,cc,cc
DTL,33333333,3333333333333333,33333333333,Y,Y,dd,dd
DTL,44444444,4444444444444444,44444444444,Y,Y,ss,ss
DTL,55555555,5555555555555555,55555555555,Y,Y,qq,qq
ملف جديد
DTL,11111111,1111111111111111,11111111111,Y,Y,xx,xx
DTL,22222222,2222222222222222,22222222222,Y,N,cc,cc
DTL,44444444,4444444444444444,44444444444,Y,Y,ss,ss
DTL,55555555,5555555555555555,55555555555,Y,Y,qq,qq
DTL,77777777,7777777777777777,77777777777,N,N,ee,ee
ملف إلاخراج
أريد مقارنة ملفات CSV القديمة والجديدة والعثور على التغييرات التي تم إجراؤها في الملف الجديد وتحديث علامة للإشارة إلى هذه التغييرات
u - إذا تم تحديث سجل الملف الجديد d - إذا تم حذف سجل موجود في الملف القديم في الملف الجديد n - إذا كان السجل الموجود في الملف الجديد غير متوفر في الملف القديم
ملف الإخراج عينة هو هذا.
DTL,11111111,1111111111111111,11111111111,Y,Y,xx,xx U
DTL,22222222,2222222222222222,22222222222,Y,N,cc,cc U
DTL,33333333,3333333333333333,33333333333,Y,Y,dd,dd D
DTL,77777777,7777777777777777,77777777777,N,N,ee,ee N
لقد استخدمت أمر diff ولكنه سيكرر السجل المحدث أيضًا وهو ما لا أريده.
DTL,11111111,1111111111111111,11111111111,Y,N,xx,xx
DTL,22222222,2222222222222222,22222222222,Y,Y,cc,cc
DTL,33333333,3333333333333333,33333333333,Y,Y,dd,dd
---
DTL,11111111,1111111111111111,11111111111,Y,Y,xx,xx
DTL,22222222,2222222222222222,22222222222,Y,N,cc,cc
5a5
DTL,77777777,7777777777777777,77777777777,N,N,ee,ee
لقد استخدمت أمر AWK ذو السطر الواحد لتصفية سجلاتي أيضًا
awk 'NR==FNR{A[$1];next}!($1 in A)' FS=: old.csv new.csv
المشكلة في هذا هي عدم حصولي على السجلات التي تنتمي إلى الملف القديم فقط.الذي
DTL,33333333,3333333333333333,33333333333,Y,Y,dd,dd
لقد بدأت أيضًا برنامج نصي bash مدفوعًا لتحقيق ذلك ولكن لم أجد الكثير من المساعدة مع مثال جيد.
myscript.awk
BEGIN {
FS = "," # input field seperator
OFS = "," # output field seperator
}
NR > 1 {
#flag
# N - new record D- Deleted U - Updated
id = $1
name = $2
flag = 'N'
# This prints the columns in the new order. The commas tell Awk to use the character set in OFS
print id,name,flag
}
>> awk -f myscript.awk old.csv new.csv > formatted.csv
المحلول
هذا قد عمل لك:
diff -W999 --side-by-side OLD NEW |
sed '/^[^\t]*\t\s*|\t\(.*\)/{s//\1 U/;b};/^\([^\t]*\)\t*\s*<$/{s//\1 D/;b};/^.*>\t\(.*\)/{s//\1 N/;b};d'
DTL,11111111,1111111111111111,11111111111,Y,Y,xx,xx U
DTL,22222222,2222222222222222,22222222222,Y,N,cc,cc U
DTL,33333333,3333333333333333,33333333333,Y,Y,dd,dd D
DTL,77777777,7777777777777777,77777777777,N,N,ee,ee N
حل awk على نفس المنوال:
diff -W999 --side-by-side OLD NEW |
awk '/[|][\t]/{split($0,a,"[|][\t]");print a[2]" U"};/[\t] *<$/{split($0,a,"[\t]* *<$");print a[1]" D"};/>[\t]/{split($0,a,">[\t]");print a[2]" N"}'
DTL,11111111,1111111111111111,11111111111,Y,Y,xx,xx U
DTL,22222222,2222222222222222,22222222222,Y,N,cc,cc U
DTL,33333333,3333333333333333,33333333333,Y,Y,dd,dd D
DTL,77777777,7777777777777777,77777777777,N,N,ee,ee N
نصائح أخرى
من المحتمل أن تكون نقطة البداية الجيدة هي:
diff -e OLD NEW
هذه المخرجات:
5a
DTL,77777777,7777777777777777,77777777777,N,N,ee,ee
.
1,3c
DTL,11111111,1111111111111111,11111111111,Y,Y,xx,xx
DTL,22222222,2222222222222222,22222222222,Y,N,cc,cc
بمعنى أنه أضاف سجلاً في السطر 5 (5أ) وقام بتغيير السجلات في السطرين 1 و3 (1،3ج).
إذا لم تتمكن من استخدام هذا التنسيق كما هو (والذي سيكون من الجيد استخدام معيار) فستحتاج إلى كتابة برنامج نصي يحوله إلى التنسيق الذي تصفه.