awk Объединить два файла на основе общего поля и распечатать сходства и различия - PullRequest
2 голосов
/ 18 декабря 2010

У меня есть два файла, которые я хотел бы объединить в третий, но мне нужно видеть оба, когда они разделяют общее поле и где они различаются. Так как в других полях есть небольшие различия, я не могу использовать инструмент сравнения, и я подумалэто можно сделать с помощью awk.

Файл 1:

aWonderfulMachine             1   mlqsjflk          
AnotherWonderfulMachine     2   mlksjf          
YetAnother WonderfulMachine 3   sdg         
TrashWeWon'tBuy             4   jhfgjh          
MoreTrash                     5   qsfqf         
MiscelleneousStuff           6  qfsdf           
MoreMiscelleneousStuff       7  qsfwsf

Файл2:

aWonderfulMachine             22    dfhdhg          
aWonderfulMachine             23    dfhh            
aWonderfulMachine             24    qdgfqf          
AnotherWonderfulMachine     25    qsfsq         
AnotherWonderfulMachine     26    qfwdsf            
MoreDifferentStuff           27    qsfsdf           
StrangeStuffBought           28    qsfsdf

Желаемый вывод:

aWonderfulMachine   1   mlqsjflk    aWonderfulMachine   22  dfhdhg
                                     aWonderfulMachine  23  dfhdhg
                                     aWonderfulMachine  24  dfhh
AnotherWonderfulMachine 2   mlksjf  AnotherWonderfulMachine 25  qfwdsf
                                       AnotherWonderfulMachine  26  qfwdsf
File1
YetAnother WonderfulMachine 3   sdg         
TrashWeWon'tBuy             4   jhfgjh          
MoreTrash                     5   qsfqf         
MiscelleneousStuff           6   qfsdf          
MoreMiscelleneousStuff       7   qsfwsf         
File2                   
MoreDifferentStuff          27  qsfsdf          
StrangeStuffBought          28  qsfsdf  

У меня естьпробовал несколько скриптов awks тут и там, но они либо основаны только на двух полях, и я не знаю, как изменить вывод, либо они удаляют дубликаты, основываясь только на двух полях, и т. д. (я новичок в этом иСинтаксис awk жесткий).Заранее большое спасибо за вашу помощь.

Ответы [ 2 ]

2 голосов
/ 18 декабря 2010

Вы можете очень близко подойти, используя эти три команды:

join <(sort file1) <(sort file2)
join -v 1 <(sort file1) <(sort file2)
join -v 2 <(sort file1) <(sort file2)

Это предполагает оболочку, такую ​​как Bash, которая поддерживает подстановку процессов (<()).Если вы используете оболочку, которая не имеет, файлы должны быть предварительно отсортированы.

Чтобы сделать это в AWK:

#!/usr/bin/awk -f
BEGIN { FS="\t"; flag=1; file1=ARGV[1]; file2=ARGV[2] }
FNR == NR { lines1[$1] = $0; count1[$1]++; next }  # process the first file
{   # process the second file and do output
    lines2[$1] = $0;
    count2[$1]++;
    if ($1 != prev) { flag = 1 };
    if (count1[$1]) {
        if (flag) printf "%s ", lines1[$1];
        else printf "\t\t\t\t\t"
        flag = 0;
        printf "\t%s\n", $0
    }
    prev = $1
}
END { # output lines that are unique to one file or the other
    print "File 1: " file1
    for (i in lines1) if (! (i in lines2)) print lines1[i]
    print "File 2: " file2
    for (i in lines2) if (! (i in lines1)) print lines2[i]
}

Для запуска:

$ ./script.awk file1 file2

Строки не будут выводиться в том же порядке, в котором они появляются во входных файлах.Второй входной файл (file2) необходимо отсортировать, так как в сценарии предполагается, что похожие строки находятся рядом.Возможно, вы захотите настроить вкладки или другой интервал в сценарии.Я мало что сделал в этом отношении.

1 голос
/ 18 декабря 2010

Один из способов сделать это (хотя и с жестко закодированными именами файлов):

BEGIN {
    FS="\t"; 
    readfile(ARGV[1], s1); 
    readfile(ARGV[2], s2); 
    ARGV[1] = ARGV[2] = "/dev/null"
}
END{
    for (k in s1) {
    if ( s2[k] ) printpair(k,s1,s2);
    }
    print "file1:"
    for (k in s1) {
    if ( !s2[k] ) print s1[k];
    }
    print "file2:"
    for (k in s2) {
    if ( !s1[k] ) print s2[k];
    }
}
function readfile(fname, sary) {
    while ( getline <fname ) {
    key = $1;
    if (sary[key]) {
        sary[key] = sary[key] "\n" $0; 
    } else {
        sary[key] = $0;
    };
    }
    close(fname);
}
function printpair(key, s1, s2) {
    n1 = split(s1[key],l1,"\n");
    n2 = split(s2[key],l2,"\n");
    for (i=1; i<=max(n1,n2); i++){
    if (i==1) {
        b = l1[1]; 
        gsub("."," ",b);
    }
    if (i<=n1) { f1 = l1[i] } else { f1 = b };
    if (i<=n2) { f2 = l2[i] } else { f2 = b };
    printf("%s\t%s\n",f1,f2);
    }
}
function max(x,y){ z = x; if (y>x) z = y; return z; }

Не особенно элегантно, но он обрабатывает множество случаев.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...