Como posso chamar bc de dentro do awk neste caso?

3

OK, então eu amo meu awk , mas sim, ele tem problemas de precisão e, infelizmente, não há nenhuma maneira fácil para eu instalar as extensões de multi-precisão conhecidas como gawkextlib .

O que eu estou fazendo é, eu estou trabalhando através de problemas em rosalind.info usando shell one-liners. Eu acho que não é difícil para mim realizar os cálculos necessários em fitas de DNA / RNA usando esses shell one-liners dentro do prazo de cinco minutos definido pelo site.

Enfim, estou preso a esse problema, mas sempre quero aprimorar meu conhecimento das ferramentas do Linux. Nesse caso, preciso chamar bc de awk .

O comando bc deve ser:

bc <<< "scale=1000; $1/$2"

Em que $1 e $2 são as duas colunas de texto com as quais estou trabalhando em awk .

O comando awk é derivado de algumas funções do shell que escrevi:

nucleic-line () {
sed 's/\(.\)/\n/g' < $@
}

gc-numeric-count () {
n=$(nucleic-line $@ | wc -l)
m=$(nucleic-line $@ | grep -v "[AT]" | wc -l)
echo $m $n
}
export -f gc-numeric-count

column-percent-count () {
for f in $@; do gc-numeric-count $f; done | awk '{a = $1/$2 | print a * 100}'
}

Para os meus propósitos, awk '{a = $1/$2 | print a * 100}' não é preciso o suficiente. Ele obtém a porcentagem de guanina e citosina correta, mas eu preciso disso para mais casas decimais do que o awk pode fornecer. Como eu disse, infelizmente não consigo instalar o gawkextlib . Preciso de precisão arbitrária, então preciso usar bc . Mas eu também quero poder processar colunas, como eu posso em awk .

Então, como posso alterar a última linha da última expressão para usar o comando bc em $1 e $2 ?

    
por ixtmixilix 18.12.2012 / 21:37

3 respostas

2

Seu problema é que você está levando o shell para o que não é: uma linguagem de programação. Um shell é antes de tudo um interpretador de linha de comando. Scripts shell são scripts. Você está implementando a lógica, o algoritmo do seu problema na sintaxe do shell, então você está indo pelo caminho errado.

Existem problemas óbvios no seu código, como variáveis não citadas. Mas apesar de tudo, é feio executar muitos comandos (como um shell é uma ferramenta para executar comandos, não linguagens de programação) apenas para encontrar a proporção de caracteres diferentes de A e T em um arquivo.

Além disso, o awk usa números flutuantes de 64 bits internamente. Você tem certeza que precisa de mais precisão do que isso? Se esses números são para ser usados por algo que tem mais precisão do que isso, você não pode usar esse alguma coisa para fazer a coisa toda?

Para responder à sua pergunta, você faria:

$ echo 1 3 | awk -vRS= '{("echo scale=300\;" $1 "/" $2 "|bc -l") | getline; print}'
.3333333333333333333333333333333333333333333333333333333333333333333\
33333333333333333333333333333333333333333333333333333333333333333333\
33333333333333333333333333333333333333333333333333333333333333333333\
33333333333333333333333333333333333333333333333333333333333333333333\
33333333333333333333333333333

Mas você pode facilmente ver como isso é inútil: awk executando um shell e dois comandos para cada linha de entrada, lendo sua saída e imprimindo novamente ... Até mesmo o shell externo poderia ter feito um trabalho tão bom com menos problemas .

Um pouco menos bobo para abordá-lo, se você ainda quiser usar o awk, seria:

echo 1 3 | awk 'BEGIN{print "scale=300"}{print $1"/"$2}' | bc

Dessa vez, apenas um comando awk e um bc .

É bastante óbvio para mim que você precisa de uma linguagem de programação real aqui (perl, ruby, python vem à mente). Você pode chamar o interpretador para essa linguagem de programação a partir de um script de shell, mas por favor apenas uma vez: apenas uma invocação deve ser suficiente para fazer a coisa toda.

    
por 18.12.2012 / 22:00
0

Sem saber o resto do seu script (não sei se você está confiando nos valores de retorno $ m $ n em outro lugar) - você considerou isso?

gc-numeric-count () {
  n=$(nucleic-line $@ | wc -l)
  m=$(nucleic-line $@ | grep -v "[AT]" | wc -l)
  echo "scale=1000;${m}/${n"}
}
export -f gc-numeric-count

column-percent-count () {
  for f in $@; do gc-numeric-count $f | bc -l; done 
}
    
por 19.12.2012 / 04:13
0

Não vejo problema em passar variáveis. Além disso, o GNU dc (incluído em bc) é muito mais fácil para cálculos embutidos, menos tubulação e polimento reverso:

print '355 113' | awk -vRS='' '{"dc -e \"1000k"$1" "$2"/pq\"" | getline; print; close(dc)}
Concorde com Stephane que o shell faz o trabalho de pista, awk faz o trabalho de formatação, e o cálculo deve ser dc

    
por 19.12.2012 / 10:10