сравнить два файла на уровне ключа (id) и отобразить различия на уровне столбца

Я ищу способ сравнить два файла на уровне ключа (id) и отобразить изменения на уровне столбца.

file_1.txt  
id|description|name|date  
1|Row 1|a|2019-06-15 00:20:15:00  
2|Row 2|b|2019-06-16 15:18:10:00  
3|Row 3|c|2019-06-17 07:02:17:00  
4|Row 4|d|2019-06-25 09:00:01:00  
5|Row 5|e|2019-06-25 22:00:00:00  


file_2.txt  
id|description|name|date  
1|Row 1|a|2019-06-15 00:20:15:00  
2|Row 2|c|2019-06-16 15:18:10:00  
4|Row 4|d|2019-06-25 09:00:01:00  
5|ROW 5|b|2019-06-25 22:00:00:00  
7|Row 7|f|2019-06-17 07:02:17:00  

Вывод должен выглядеть так:

1|Row 1|a|2019-06-15 00:20:15:001|Row 1|a|2019-06-15 00:20:15:00,Match  
2|Row 2|c|2019-06-16 15:18:10:00|Row 2|b|2019-06-16 15:18:10:00No Match  
3|Row 3|c|2019-06-17 07:02:17:00,No Match  
4|Row 4|d|2019-06-25 09:00:01:004|Row 4|d|2019-06-25 09:00:01:00,Match  
5|ROW 5|b|2019-06-25 22:00:00:00|Row 5|e|2019-06-25 22:00:00:00,No Match  
7|Row 7|f|2019-06-17 07:02:17:00,No Match  

попытался использовать ниже, где файл2 используется в качестве файла драйвера для вывода вывода, поэтому он не печатает и игнорирует строку с идентификатором 3, поскольку ее нет в файле2.txt

awk -F, 'NR==FNR{ arr[$1]=$0; next } { print $0 (arr[$1]==$0?arr[$1]",Match":arr[$1]",No Match") }' OFS=, file1.txt file2.txt

id|описание|имя|дата,Соответствие
1|Строка 1|a|2019-06-15 00:20:15:001|Строка 1|a|2019-06-15 00:20:15:00, Совпадение
2|Ряд 2|c|2019-06-16 15:18:10:00,Нет совпадений
4|Ряд 4|d|2019-06-25 09:00:01:004|Ряд 4|d|2019-06-25 09:00:01:00,Соответствует
5|Ряд 5|b|2019-06-25 22:00:00:00,Нет соответствия
7|Строка 7 |f|2019-06-17 07:02:17:00,Нет совпадений

Не уверен, почему он печатает только записи из файла1 и файла2, когда есть совпадение.

Чтобы дать больше информации об этом - я пытаюсь использовать эту команду awk, чтобы найти различия в ч/б файлах, а затем создать отчет, который в основном показывает, какие столбцы имеют разные значения. в идеале конечный результат будет выглядеть так

id|Change| Columns  
1|No Change|NA  
2|Change|name  
3|Exists only in file 1|NA  
4|No Change|NA  
5|Change|description,name  
7|Exists only in file 2|NA 

Был бы очень признателен за руководство от всех экспертов здесь, чтобы достичь этого.


person tech_sms169    schedule 20.06.2019    source источник
comment
Вы используете неправильный разделитель полей — ваши файлы разделены вертикальной чертой, а не запятыми.   -  person glenn jackman    schedule 20.06.2019


Ответы (2)


Читая ваш запрос, легче выполнить всю задачу, а не промежуточный шаг.

Вот скрипт awk, выполняющий последнюю задачу.

script.awk

BEGIN {FS = OFS = "|"; f[2]="descr"; f[3] = "name"; f[4] = "date "}
FNR == NR {        # read first input file
    lines[$1] = $0;
    next;
}
{                  # read scond input file
    if ($1 in lines) { # index exist in file 1
        if ($0 == lines[$1]) { # compare indexed lines
            print $1, "Same", "NA";
        } else { # indexed lines differ
            split(lines[$1], file1Fields); # read all fields from file 1 line
            unmatchedFields = "";
            for (m = 2; m <= 4; m++) {
                if (file1Fields[m] != $m) { # compare each field
                    fieldsSeparator = length(unmatchedFields) ? "," : "";
                    unmatchedFields = unmatchedFields fieldsSeparator f[m];
                }
            }
            print $1, "change", unmatchedFields;
        }
        delete lines[$1]; # clean handled lines from file1
    } else { # index not seen in file 1, it is only in file 2
        print $1, "only in file 2", "NA";
    }
}
END {
    for (j in lines) {  # index only in file 1
        print j, "only in file 1", "NA";
    }
}

input.1.txt

id|description|name|date  
1|Row 1|a|2019-06-15 00:20:15:00  
2|Row 2|b|2019-06-16 15:18:10:00  
3|Row 3|c|2019-06-17 07:02:17:00  
4|Row 4|d|2019-06-25 09:00:01:00  
5|Row 5|e|2019-06-25 22:00:00:00  

input.2.txt

id|description|name|date  
1|Row 1|a|2019-06-15 00:20:15:00  
2|Row 2|c|2019-06-16 15:18:10:00  
4|Row 4|d|2019-06-25 09:00:01:00  
5|ROW 5|b|2019-06-25 22:00:00:00  
7|Row 7|f|2019-06-17 07:02:17:00 

Бег:

awk -f script.awk input.1.txt input.2.txt |sort

выход:

1|Same|NA
2|change|name
3|only in file 1|NA
4|Same|NA
5|change|descr,name,date
7|only in file 2|NA
id|Same|NA
person Dudi Boy    schedule 20.06.2019
comment
Спасибо Дуди. Это прекрасно работает. Любые мысли о более раннем решении получения синтаксической ошибки на ARGIND? - person tech_sms169; 20.06.2019
comment
Танкс @tech_sms169. Пожалуйста, выразите свою благодарность, проголосовав за участников, и выберите ответ. - person Dudi Boy; 21.06.2019
comment
Я не исследовал другие решения вашего квеста, прежде чем внести свой вклад. Возможно я должен. - person Dudi Boy; 21.06.2019

С GNU awk для массивов массивов, gensub(), sorted_in и ARGIND:

$ cat tst.awk
BEGIN { FS=OFS="|" }
FNR==1 { next }
{ vals[$1][ARGIND] = gensub("^[^"FS"]+["FS"]","",1) }
END {
    PROCINFO["sorted_in"] = "@ind_num_asc"
    for (id in vals) {
        print id, \
           (1 in vals[id] ? vals[id][1] : "N/A"),
           (2 in vals[id] ? vals[id][2] : "N/A"),
           (vals[id][1] == vals[id][2] ? "" : "No ") "Match"
    }
}

$ awk -f tst.awk file1 file2
1|Row 1|a|2019-06-15 00:20:15:00|Row 1|a|2019-06-15 00:20:15:00|Match
2|Row 2|b|2019-06-16 15:18:10:00|Row 2|c|2019-06-16 15:18:10:00|No Match
3|Row 3|c|2019-06-17 07:02:17:00|N/A|No Match
4|Row 4|d|2019-06-25 09:00:01:00|Row 4|d|2019-06-25 09:00:01:00|Match
5|Row 5|e|2019-06-25 22:00:00:00|ROW 5|b|2019-06-25 22:00:00:00|No Match
7|N/A|Row 7|f|2019-06-17 07:02:17:00|No Match

или, если вы предпочитаете:

$ awk -f tst.awk file2 file1
1|Row 1|a|2019-06-15 00:20:15:00|Row 1|a|2019-06-15 00:20:15:00|Match
2|Row 2|c|2019-06-16 15:18:10:00|Row 2|b|2019-06-16 15:18:10:00|No Match
3|N/A|Row 3|c|2019-06-17 07:02:17:00|No Match
4|Row 4|d|2019-06-25 09:00:01:00|Row 4|d|2019-06-25 09:00:01:00|Match
5|ROW 5|b|2019-06-25 22:00:00:00|Row 5|e|2019-06-25 22:00:00:00|No Match
7|Row 7|f|2019-06-17 07:02:17:00|N/A|No Match

«Н/Д» поможет вам определить, в каком из двух файлов не было строки для данного идентификатора. Если вам это не нравится, сделайте массаж в соответствии с вашими потребностями.


Обновление: вот как это сделать с любым awk и sort:

$ cat tst.awk
BEGIN { FS=OFS="|" }
FNR==1 { argind++; next }
{
    id = $1
    ids[id]
    sub("^[^"FS"]+["FS"]","")
    vals[id,argind] = $0
}
END {
    for (id in ids) {
        print id, \
           ((id,1) in vals ? vals[id,1] : "N/A"),
           ((id,2) in vals ? vals[id,2] : "N/A"),
           (vals[id,1] == vals[id,2] ? "" : "No ") "Match"
    }
}

$ awk -f tst.awk file1 file2 | sort -t'|' -k1,1n
1|Row 1|a|2019-06-15 00:20:15:00|Row 1|a|2019-06-15 00:20:15:00|Match
2|Row 2|b|2019-06-16 15:18:10:00|Row 2|c|2019-06-16 15:18:10:00|No Match
3|Row 3|c|2019-06-17 07:02:17:00|N/A|No Match
4|Row 4|d|2019-06-25 09:00:01:00|Row 4|d|2019-06-25 09:00:01:00|Match
5|Row 5|e|2019-06-25 22:00:00:00|ROW 5|b|2019-06-25 22:00:00:00|No Match
7|N/A|Row 7|f|2019-06-17 07:02:17:00|No Match
person Ed Morton    schedule 20.06.2019
comment
Большое спасибо, Эд. Я новичок в тарабарщине, поэтому очень ценю вашу помощь. Попытался выполнить код (закомментировал несколько строк для тестирования), но выдает синтаксическую ошибку BEGIN { FS=OFS=| } FNR==1 { далее} { vals[$1][ARGIND] = gensub(^[^FS]+[FS],,1) } END { PROCINFO[sorted_in] = @ind_num_asc for (id in vals) { print id } # (1 в vals[id] ? vals[id][1] : н/д), # (2 в vals[id] ? vals[id][2] : н/д), # (vals[ id][1] == vals[id][2] ? : Нет ) Совпадение # } } - person tech_sms169; 20.06.2019
comment
Из сообщения об ошибке в ответе, который вы разместили, похоже, что вы не используете GNU awk, который, как я сказал, был необходим . Что выводит awk --version? В любом случае, я добавил версию, которая будет работать в любом awk. - person Ed Morton; 21.06.2019