Compare dois arquivos com a primeira coluna e remova a linha duplicada do segundo arquivo no shell script

9

Vou fazer minha pergunta com um exemplo. Eu tenho 2 arquivos:

Arquivo nº 1:

118D FC300_R5_TP  FX.B      32775       2112   6       2038   6       2112   0
118E FC300_R5_TP  FX.B      32775       2136   7       2065   6       2136   0
118F FC300_R5_TP  FX.B      32775       2124   6       2064   6       2124   0
1190 FC300_R5_TP  FX.B     819210     814632  99     814609  99     814632   0
1191 FC300_R5_TP  FX.B     819210     104100  13     103714  13     104100   0
1192 FC300_R5_TP  FX.B    1638420    1609476  98    1609402  98    1609476   0
1196 FC300_R5_TP  FX.B    1638420    1638432 100    1638379 100    1638432   0
119A FC300_R5_TP  FX.B    3276840    3271776 100    3271698 100    3271776   0
119E FC300_R5_TP  FX.B    3276840    3264120 100    3264034 100    3264120   0
11A2 FC300_R5_TP  FX.B    3276840    2328648  71    2328546  71    2328648   0
11A6 FC300_R5_TP  FX.B    3276840    2328444  71    2328355  71    2328444   0
11AA FC300_R5_TP  FX.B    3276840    2328528  71    2328403  71    2328528   0
11AE FC300_R5_TP  FX.B    3276840    2328648  71    2328468  71    2328648   0
11B2 FC300_R5_TP  FX.B    3276840    2130000  65    2129766  65    2130000   0
173A FC300_R5_TP  FX.B    6553680    6478572  99    6477747  99    6478572   0

Arquivo nº 2:

11AA FC300_R5_TP  FX.B    3276840    2328528  71    2328403  71    2328528   0
11AE FC300_R5_TP  FX.B    3276840    2328648  71    2328468  71    2328648   0
11B2 FC300_R5_TP  FX.B    3276840    2130000  65    2129766  65    2130000   0
173A FC300_R5_TP  FX.B    6553680    6478572  99    6477747  99    6478572   0
0BDB FC600_R5_TP  FX.B   33554640    6044364  18    6033105  18    6044364   0
0BDC FC600_R5_TP  FX.B   33554640    6613536  20    6481974  19    6613536   0
0BDD FC600_R5_TP  FX.B   33554640    4435848  13    4057170  12    4435848   0
0BDE FC600_R5_TP  FX.B   33554640    6620868  20    6249518  19    6620868   0

Saída desejada

Arquivo nº 3:

0BDB FC600_R5_TP  FX.B   33554640    6044364  18    6033105  18    6044364   0
0BDC FC600_R5_TP  FX.B   33554640    6613536  20    6481974  19    6613536   0
0BDD FC600_R5_TP  FX.B   33554640    4435848  13    4057170  12    4435848   0
0BDE FC600_R5_TP  FX.B   33554640    6620868  20    6249518  19    6620868   0

Gostaria de comparar o arquivo 1 e o arquivo 2 usando as primeiras colunas e remover toda a linha ou linha do arquivo 2, onde eles correspondem no arquivo 1. Eu também gostaria de salvar os resultados em um terceiro arquivo, arquivo # 3.

    
por Rahul Rana 13.09.2013 / 10:51

5 respostas

10

Você pode usar awk para isso:

awk 'FNR==NR{a[$1];next};!($1 in a)' file1 file2 > file3

Explicação:

  • FNR == NR : esse teste é verdadeiro quando o número de registros é igual ao número de registros no arquivo. Isso só é válido para o primeiro arquivo, pois o segundo arquivo NR será igual ao número de linhas do arquivo1 + FNR .

  • a[$1] : crie um índice de elemento de matriz do primeiro campo do arquivo1.

  • next : pule para o próximo registro para que nenhum processamento seja feito no arquivo1.

  • !($1 in a) : Veja se o primeiro campo ($ 1) está presente na matriz, ou seja, no arquivo1, e imprima a linha inteira (para o arquivo3).

Baseado em um dos exemplos do #awk wiki .

    
por 13.09.2013 / 11:07
8
export LC_ALL=C
comm -13 <(sort f1) <(sort  f2)

Informaria as linhas que estão apenas em f2 .

export LC_ALL=C
join -v2 <(sort f1) <(sort f2)

Informaria as linhas de f2 cujo primeiro campo não foi encontrado como o primeiro campo em qualquer linha de f1 .

(você precisa de um shell com suporte para substituição de processo como ksh93 , zsh ou bash ).

    
por 13.09.2013 / 11:50
2

Apenas por diversão, eis uma solução em Perl:

#!/usr/bin/perl

# create names lookup table from first file
my %names;
while (<>) {
    (my $col1)= split / /, $_;
    $names{$col1} = 1;
    last if eof;
}

# scan second file
while (<>) {
    print if /^(\S+).*/ && not $names{$1};
}

Exemplo

$ ./showdiffs.pl file1  file2
0BDB FC600_R5_TP  FX.B   33554640    6044364  18    6033105  18    6044364   0
0BDC FC600_R5_TP  FX.B   33554640    6613536  20    6481974  19    6613536   0
0BDD FC600_R5_TP  FX.B   33554640    4435848  13    4057170  12    4435848   0
0BDE FC600_R5_TP  FX.B   33554640    6620868  20    6249518  19    6620868   0

Detalhes

A solução Perl acima é composta por 2 loops. O primeiro loop lê todas as linhas de file1 e cria um hash, %names , onde cada coluna identificada é adicionada.

$names{11AA} = 1;

O segundo loop while é executado sobre o segundo arquivo, file2 , e a coluna 1 de cada linha é identificada usando a expressão regular:

^(\S+).*

O texto acima diz que, desde o início da linha, corresponde a tudo que não é um espaço e o salva na variável temporária $1 . É salvo envolvendo os parênteses em volta dele. O .* diz que corresponde a todo o resto da linha.

O próximo bit dessas linhas diz para procurar a coluna 1 bit que acabamos de salvar em $1 no %names hash:

$names{$1}

Se estiver presente lá, não queremos imprimi-lo. Se não estiver lá, imprima-o.

    
por 13.09.2013 / 16:31
2

Método 1 # Bash

#!/usr/bin/env bash
file1=$1
file2=$2

[[ $# -ne 2 ]]  && { echo -e "\n\tUsage: \t$0 file1 file2\n"; exit 1; }

while read line
do

        if ! grep -q "${line%% .*}" $file1; then
                echo "${line}"
        fi

done < $file2

Método 2 # Somente Grep

grep -v "$(< file1)" file2

grep está funcionando, mas não garante

    
por 14.09.2013 / 09:55
1

Vamos ver como

Arquivo # 1: file1.txt

Arquivo # 2: file2.txt

Em seguida, execute o seguinte no terminal

fgrep -vf test1.txt test2.txt > output.txt

output.txt conterá os resultados desejados.

Explicação:

fgrep : print lines matching a pattern (from manual page)
-v  : get only non-matching rows
-f : obtain PATTERN from FILE (from manual page)
    
por 20.05.2014 / 14:18