operação aritmética em uma coluna aninhada em um arquivo delimitado por tabulação

0

Eu tenho um arquivo de texto delimitado por tabulação contendo Column1...Columnn colunas e R1 to Rn rows. Em algumas das colunas, há vários campos aninhados com um identificador e, em seguida, separados por ponto-e-vírgula (mostrado no arquivo de imagem de amostra anexado na cor vermelha). Para ser preciso, estou anexando um instantâneo de amostra do arquivo.

Aqui, os dados da coluna 6 INFO têm vários campos aninhados, como DP; RPB; AF1; AC1; DP4;... etc.

Tarefa: De inputfile.txt , na Coluna6 INFO , para escolher o campo DP4=a,b,c,d e precisa fazer operações aritméticas simples nos valores DP4=a,b,c,d (marcados em vermelho na imagem) , como (c+d)/(a+b+c+d) - > e cole os resultados de cada linha como nova coluna INFOextra no mesmo arquivo.

Como isso pode ser feito no script de shell e unix?

    
por panbar 12.03.2016 / 22:05

1 resposta

0

awk '$1=="ID" {print $0 "\tINFOextra"; next}; NF { info=$6; gsub(/.*;DP4=|;MQ=.*/, "", info); split(info, a, /,/); print $0 "\t" (a[3]+a[4])/(a[1]+a[2]+a[3]+a[4])}' inputfile.txt > outputfile.txt
# then check the content outputfile.txt and rename it if important

Como você pode ver, a solução é muito semelhante à resposta dada à sua pergunta anterior, e não mais de forma alguma. É porque o awk é extremamente ajustado para servir em problemas como o seu. Eu sugiro dar uma olhada em sua página de manual ( link ) para ver como é simples em comparação com outros (e linguagens mais gerais).

Se vários arquivos de entrada devem ser processados em vários arquivos de saída com os nomes apropriados, as opções são as seguintes:

  • crie um loop no shell e inicie um processo awk para cada arquivo, um por um
  • faz o awk gravar a saída em arquivos cujos nomes são dependentes do nome do arquivo de entrada atual que a informação é armazenada na variável FILENAME do awk que é automaticamente ajustada durante o processo. Dentro do redirecionamento do código awk pode ser usado com a mesma sintaxe e resultado similar que o shell usa:

    awk '$ 1 == "ID" {print $ 0 "\ tINFOextra" > FILENAME ".out"; Próximo}; NF {info = $ 6; gsub (/.*; DP4 = |; MQ =. * /, "", info); dividir (informação, a, /, /); print $ 0 "\ t" (a [3] + a [4]) / (a [1] + a [2] + a [3] + a [4]) > FILENAME ".out"} 'inputfile1.txt inputfile2.txt

Aqui, cada instância de inputfileN.txt terá um arquivo inputfileN.txt.out correspondente. FILENAME é uma string simples, portanto, qualquer tipo de manipulação dos arquivos de saída é válido.

Quando a especificação se torna complicada, de modo que o campo adicional deve aparecer em uma posição interna (não no começo ou no final), crie uma sub-rotina (chamada function in awk) para criar as linhas de saída. Essa função aqui percorre todos os campos, imprime-os como de costume, mas onde o campo adicional deve aparecer, ele escreve que depois do n-1-ésimo e antes do n-ésimo campo, tornando-se o n-ésimo. Agora, vale a pena colocar o código awk em seu próprio arquivo:

$ cat bio.awk


function myprint( str) {
   for (i=1; i<=NF; ++i) {
      printf "%s", $i  > FILENAME ".out"
      if (i==44)
         printf "\t%s", str  >> FILENAME ".out"
      if (i!=NF)
         printf "\t"  >> FILENAME ".out"
   }
   print ""  >> FILENAME ".out"
}

$1=="ID" {
   myprint( "INFOextra")
   next
}

NF {
   info=$6
   gsub(/.*;DP4=|;MQ=.*/, "", info)
   split(info, a, /,/)
   myprint( (a[3]+a[4])/(a[1]+a[2]+a[3]+a[4]) )
}

A chamada resulta em uma linha de comando mais curta e limpa:

awk -f bio.awk inputfile1.txt inputfile2.txt
    
por 12.03.2016 / 23:00