Como alterar o texto em lote no arquivo com base na lista de entradas

3

Eu tenho uma lista grande de dados, como

FILE1 (4600 linhas)

Genome  Gene    Boolean
E15-12  VFG000923   1
E15-13  VFG000924   1
E15-14  VFG000926   1
E15-15  VFG000928   1
E15-16  VFG000930   1
E15-17  VFG000932   1
E15-18  VFG000933   0
E15-19  VFG001448   0
E15-24  VFG013465   1

Eu quero sub a informação em col2 para se parecer com:

FILE2 (180 linhas)

VFG000923|fepA
VFG000924|fepB
VFG000926|fepD
VFG000928|fepG
VFG000930|entF
VFG000932|entE
VFG000933|entB
VFG001448|kpsD
VFG001450|kpsM
VFG044165|entS

Fora

Genome   Gene         Boolean
E15-12  VFG000923|fepA  1
E15-13  VFG000924|fepB  1
E15-14  VFG000926|fepD  1
E15-15  VFG000928|fepG  1
E15-16  VFG000930|entF  1
E15-17  VFG000932|entE  1
E15-18  VFG000933|entB  0
E15-19  VFG001448|kpsD  0
E15-20  VFG001450|kpsM  1

Usando código por @ val0x00ff (veja os comentários)

Genome  Gene    Boolean

E15-14 VFG000923|fepA 1

E15-14 VFG000924|fepB 0

E15-14 VFG000926|fepD 1

E15-14 VFG000928|fepG 0

Existe uma maneira de fazer isso com sed ou awk?

    
por AudileF 03.05.2017 / 13:01

3 respostas

2

com sed :

sed '/|/{H;d;};G;s/\([A-Z0-9]*\)\(.*\n\)\(|[^[:cntrl:]]*\)//;P;d' FILE2 FILE1

deve fazer o truque. É uma adaptação de esta resposta . A explicação detalhada está lá.

    
por 03.05.2017 / 17:03
2

Isso deve funcionar:

$ awk 'NR==FNR{k=sub(/\|.*/,$1); a[k]=$1; next} ($2 in a){$2=a[$2]}1' file2 file
Genome Gene Boolean
E15_14 VFG000923|fepA 1
E15_14 VFG000924|fepB 1
E15_14 VFG000926|fepD 0
E15_14 VFG000928|fepG 1
E15_14 VFG000930|entF 0
E15_14 VFG000932|entE 0
E15_14 VFG000933|entB 1
E15_14 VFG001448|kpsD 1
E15_14 VFG001450|kpsM 1
E15_14 VFG044165|entS 0

Ou, um pouco mais fácil de ler:

awk 'NR==FNR{
        k=sub(/\|.*/,$1); 
        a[k]=$1; 
        next
    } 
    ($2 in a){
        $2=a[$2]
    }1' file2 file

Explicação

  • NR==FNR{ } : NR é o número da linha de entrada atual e FNR é o número da linha do arquivo atual. Ao ler mais de um arquivo, os dois serão iguais apenas durante a leitura do primeiro arquivo.
  • k=sub(/\|.*/,$1); : remova a parte depois do | da linha (isto só acontece para o primeiro arquivo por causa do NR==FNR como explicado acima).
  • a[k]=$1; : salve o primeiro campo do primeiro arquivo como um valor na matriz a cuja chave é o nome do gene (o primeiro campo com tudo após o | removido).
  • next : pule para a próxima linha. Isso garante que não executemos o próximo bloco durante a leitura do primeiro arquivo.
  • ($2 in a) : se o segundo campo existir como uma chave na matriz a (isso só será executado para o segundo arquivo).
  • $2=a[$2] : defina o segundo campo para o que foi armazenado em a para $2 .
  • 1 : esta é uma abreviação de awk para "imprimir a linha atual". funciona porque a ação padrão quando algo é avaliado como verdadeiro no awk é imprimir a linha atual. Como 1 é sempre verdadeiro, isso será impresso.
por 03.05.2017 / 14:18
1
perl -lne '
   @ARGV and %h=(%h, /(.*)\|/ => $_),next;
   !@ARGV and !$a++ and print,next;
   print s//$h{$1}/r if exists $h{(/\h\K(\S+)(?=\h)/)[0]};
' FILE2 FILE1

Explicação

  • Ao ler no arquivo menor (FILE2), preenchemos o hash %h que é keyed nos dados antes de | e o valor é toda a linha.
  • Ao ler o arquivo maior (FILE1), primeiro imprimimos a primeira linha usando: !@ARGV and !$a++ que significa @ARGV foi esvaziado e estamos vendo a variável $a pela primeira vez.
  • Nas linhas restantes, veremos se o segundo campo é identificado por meio do regex /\h\S+\h/ para ver se essa chave existe no hash %h . Quando isso for verdade, substituiremos esse campo pelo valor correspondente a essa chave.
por 05.05.2017 / 14:57