Descobrir as linhas comuns em dois arquivos usando 4 campos usando awk e UNIX

1

Eu tenho 2 arquivos. Se os campos 1, 2, 4 e 5 do arquivo 1 e do arquivo 2 corresponderem, quero imprimir toda a linha do arquivo1 e do arquivo2, um após o outro, no meu arquivo de saída.

Arquivo1:

sc2/80         20      .        A       T         86   F=5;U=4
sc2/60         55      .        G       T         76   F=5;U=4 
sc2/68         20      .        T       C         71   F=5;U=4
sc2/24         24      .        T       G         31   F=5;U=4

Arquivo2:

sc2/99         84      .        C       G         61   F=5;U=4
sc2/80         20      .        A       T         30   F=5;U=4
sc2/60         40      .        G       T         76   F=5;U=4 
sc2/30         20      .        T       C         71   F=5;U=4
sc2/24         24      .        T       G         91   F=5;U=4

Resultado esperado:

sc2/80         20      .        A       T         86       F=5;U=4
sc2/80         20      .        A       T         30       F=5;U=4
sc2/24         24      .        T       G         31       F=5;U=4
sc2/24         24      .        T       G         91       F=5;U=4

Sou novo no ramo e agradeço sua ajuda.

    
por Namrata 27.08.2013 / 11:58

4 respostas

1

Você pode usar uma matriz multidimensional:

awk 'FNR==NR{a[$1,$2,$4,$5]=$0;next}{if(b=a[$1,$2,$4,$5]){print b;print}}' file1 file2

FNR (número de registro do arquivo) é igual a NR quando o awk está processando o primeiro arquivo.

a[$1,$2]=$0 é igual a a[$1 SUBSEP $2]=$0 ou a[$1"4"$2]=$0 e ($1,$2)in a é igual a ($1 SUBSEP $2)in a ou ($1"4"$2)in a .

Você também pode substituir if(b=a[$1,$2,$4,$5]){print b;print} por if(($1,$2,$4,$5)in a){print a[$1,$2,$4,$5];print} . Se !("index" in a) , a["index"] for igual a a["index"]="" .

    
por 27.08.2013 / 12:27
1

Eu sei que você disse que não queria uma solução Perl ou Python, mas poderia ser útil para outra pessoa (e você realmente deveria aprender um desses idiomas se estivesse fazendo bioinformática).

perl -ane '$f=$F[0].$F[1]; print "$k{$f}$_" if $k{$f}; $k{$f}=$_;' file1 file2 

EXPLICAÇÃO:

A opção -a fará o Perl dividir a entrada na matriz @F , -n significa ler arquivos de entrada linha por linha e -e significa "executar o script que eu dou na linha de comando".

Portanto, $f está definido para a concatenação dos primeiros campos ( $F[0] ) e segundo ( $F[1] ). $k{$f}=$_ significa salvar a linha atual ( $_ ) como o valor em um hash (matrizes associativas em Perl) chamado k com a chave $f . Conforme lemos os arquivos, imprima a linha atual e o valor de $k{$f} se esse valor existir. Em outras palavras, se já tivermos visto uma linha que tenha os mesmos dois primeiros campos, imprima essa linha e a linha atual.

    
por 27.08.2013 / 14:49
0

Você deseja imprimir a interseção dos dois arquivos sem reordená-los (portanto, não é uma interseção definida)? Eu procuraria por algoritmos de similaridade de strings e trataria cada linha como uma letra. Você precisará modificar o algoritmo para acompanhar quais letras (linhas) são iguais e quais diferem. O grande problema é que a ordem é significativa, mas a posição não é. Além disso, talvez seja mais fácil massagear os dados reescrevendo-os para eliminar os campos com os quais você não se importa. (Ou para escrever uma função de comparação que ignora esses campos.)

Você já considerou python ou perl? Eu ouvi dizer que eles são populares no campo da bioinformática. E isso realmente parece uma tarefa de programação.

    
por 27.08.2013 / 12:08
0

Se você puder garantir que cada arquivo deve ter entradas exclusivas. Classifique os arquivos com sort -u concatenando os arquivos. Classifique novamente sem o -u e pesquise por entradas duplicadas.

Eu escrevia o pequeno roteiro, mas não consigo tirar isso da cabeça. Mas não deveria ser difícil, dada a minha abordagem.

Eu tenho um console na minha frente agora. Aqui vai:

rm -rf all; sort -u file1 > all; sort -u file2 >> all
sort all | uniq --all-repeated=separate -w 32

Se file1 file2 já estiverem classificados e não contiverem entradas duplicadas, você poderá usar este comando:

sort -m file1 file2 | uniq --all-repeated=separate -w 32

Oh, parece que isso não é bem o que você pediu, já que eu comparo linhas inteiras. Talvez outra pessoa ache isso útil.

    
por 27.08.2013 / 12:32