Como extrair vários bits de informação que aparecem em linhas diferentes no mesmo arquivo de texto

Como extrair vários bits de informação que aparecem em linhas diferentes no mesmo arquivo de texto

Estou tentando extrair o ID de sequência e o número do cluster que ocorrem em linhas diferentes no mesmo arquivo de texto.

A entrada parece

>Cluster 72
0   319aa, >O311_01007... *
>Cluster 73
0   318aa, >1494_00753... *
1   318aa, >1621_00002... at 99.69%
2   318aa, >1622_00575... at 99.37%
3   318aa, >1633_00422... at 99.37%
4   318aa, >O136_00307... at 99.69%
>Cluster 74
0   318aa, >O139_01028... *
1   318aa, >O142_00961... at 99.69%
>Cluster 75
0   318aa, >O300_00856... *

A saída desejada é o ID de sequência em uma coluna e o número do cluster correspondente na segunda.

>O311_01007  72
>1494_00753  73
>1621_00002  73
>1622_00575  73
>1633_00422  73
>O136_00307  73
>O139_01028  74
>O142_00961  74
>O300_00856  75

Alguém pode ajudar com isso?

Responder1

Com awk:

awk -F '[. ]*' 'NF == 2 {id = $2; next} {print $3, id}' input-file
  • dividimos os campos em espaços ou períodos com-F '[. ]*'
  • com linhas de dois campos, (as >Clusterlinhas), salve o segundo campo como o ID e passe para a próxima linha
  • com outras linhas, imprima o terceiro campo e o ID salvo

Responder2

Você pode usar awkpara isso:

awk '/>Cluster/{
      c=$2;
      next
    }{
      print substr($3,2,length($3)-4), c
    }' file

A primeira instrução de bloco captura o ID do cluster. A segunda instrução de bloco (a padrão) está extraindo os dados desejados e imprimindo-os.

Responder3

Aqui está uma alternativa com Ruby como one-liner:

ruby -ne 'case $_; when /^>Cluster (\d+)/;id = $1;when /, (>\w{4}_\w{5})\.\.\./;puts "#{$1} #{id}";end' input_file

ou espalhado em várias linhas:

ruby -ne 'case $_
when /^>Cluster (\d+)/
  id = $1
when /, (>\w{4}_\w{5})\.\.\./
  puts "#{$1} #{id}"
end' input_file

Acho que só é mais legível que a awkversão se você conhece Ruby e regexen. Como bônus, esse código pode ser um pouco mais robusto do que simplesmente dividir as linhas, porque procura o texto ao redor.

Responder4

Perl:

$ perl -ne 'if(/^>.*?(\d+)/){$n=$1;}else{ s/.*(>[^.]+).*/$1 $n/; print}' file 
>O311_01007 72
>1494_00753 73
>1621_00002 73
>1622_00575 73
>1633_00422 73
>O136_00307 73
>O139_01028 74
>O142_00961 74
>O300_00856 75

Explicação

  • perl -ne: leia o arquivo de entrada linha por linha ( -n) e aplique o script fornecido por -ea cada linha.
  • if(/^>.*?(\d+)/){$n=$1;}: se esta linha começar com >, encontre o trecho mais longo de números no final da linha e salve-o como $n.
  • else{ s/.*(>[^.]+).*/$1 $n/; print: se a linha não começar com >, substitua tudo pelo trecho mais longo de não- .caracteres após um >( >[^.]+), ou seja, o nome da sequência ( $1porque temoscapturadoa correspondência de regex) e o valor atual de $n.

Ou, para uma abordagem mais estranha:

$ perl -lane 'if($#F==1){$n=$F[1]}else{$F[2]=~s/\.+$//; print "$F[2] $n"}' file 
>O311_01007 72
>1494_00753 73
>1621_00002 73
>1622_00575 73
>1633_00422 73
>O136_00307 73
>O139_01028 74
>O142_00961 74
>O300_00856 75

Esta é apenas uma maneira um pouco mais complicada de executar a mesma ideia básica das várias awkabordagens. Estou incluindo-o para fins de conclusão e para os fãs de Perl. Se precisar de uma explicação, basta usar as soluções awk :).

informação relacionada