calcula a relação usando o awk

0
awk 'NR==1{$4="ratio"}NR>1{$4 = ($3)/($2)} {print $1 "\t" $2 "\t" $3 "\t" $4}' A  B

awk: cmd. line:1: (FILENAME=A FNR=18) fatal: division by zero attempted

Alguém pode ajudar com esse erro?

O que significa NR==1 e NR>1 aqui? Está em exemplos de awk; Eu não entendo Eu sei NR é o número de registros, mas por que estamos usando aqui?

    
por star 19.04.2016 / 14:50

2 respostas

2

Parece que os autores desse exemplo imaginaram o formato dos arquivos A e B como algo assim:

Arquivo A:

X Y Z
1 2 3
4 5 6

Arquivo B:

6 7 8
o o 0

O que o exemplo AWK faz é criar uma quarta coluna. NR aqui representa a linha atual que o AWK está processando. Na primeira linha, o quarto parâmetro da string "ratio" (nome da coluna), em todas as linhas seguintes, define o quarto parâmetro para o terceiro parâmetro dividido pelo segundo. O resultado:

awk 'NR==1{$4="ratio"}NR>1{$4 = ($3)/($2)} {print $1 "\t" $2 "\t" $3 "\t" $4}' A
X   Y   Z   ratio
1   2   3   1.5
4   5   6   1.2
6   7   8   1.14286
1   2   3   1.5

Quanto ao erro que você está recebendo:

awk: cmd. line:1: (FILENAME=A FNR=18) fatal: division by zero attempted

Certifique-se de que a 18ª linha do arquivo A contenha números nas colunas 2 e 3.

Você pode usar sed para converter os caracteres 'o' em 0:

cat A B | sed 's/\bo\b/0/g'

E você pode verificar se a coluna 2 é 0 e agir de acordo:

awk 'NR==1{$4="ratio"}NR>1{if($2==0) $4 = "N/A"; else $4 = ($3)/($2)}

Coloque junto, você começa:

cat A B | sed 's/\bo\b/0/g' | awk 'NR==1{$4="ratio"}NR>1{if($2==0) $4 = "N/A"; else $4 = ($3)/($2)} {print $1 "\t" $2 "\t" $3 "\t" $4}'
X   Y   Z   ratio
1   2   3   1.5
4   5   6   1.2
6   7   8   1.14286
0   0   0   N/A
    
por 19.04.2016 / 15:15
1

No exemplo dado,

awk 'NR==1{$4="ratio"}NR>1{$4 = ($3)/($2)} {print $1 "\t" $2 "\t" $3 "\t" $4}' A  B

NR é o número de registros lidos até o momento. Pode-se usá-lo em um exemplo como este para pular o cabeçalho de uma tabela como esta:

Date        Cost     Quantity
2016/04/10  12.57    3
2016/04/19  11.74    2

desde que você não pode dividir "Custo" por "Quantidade" (eles não são números).

A propósito, seus dados poderiam ter quatro (ou mais) colunas. No entanto, o awk permitirá que você atribua a colunas que não estão nos dados de entrada. Assim, o $4="ratio" inicial poderia estar alterando uma coluna existente, mas é mais provável adicionar uma coluna aos dados para refletir o cálculo em registros sucessivos.

O erro (divisão por zero) é uma questão diferente da interpretação de NR . Você pode verificar se tem dados numéricos em $2 e $3 usando um padrão, por exemplo, adicionando essa verificação:

para produzir algo como

#!/bin/sh
awk 'function isnum(v) { 
     if ( v ~ /^[0-9.]+$/ ) 
         return 1; 
     else 
         return 0; 
     } 
     (NR==1){$4="ratio"} 
     (NR>1 && NF >= 3 && isnum($2) && isnum($3) && $3 > 0){$4 = ($3)/($2)} 
     {print $1 "\t" $2 "\t" $3 "\t" $4}' A  B

A função isnum é simplificada, mas permitirá frações decimais não assinadas.

Se você preferir o script em uma única linha, lembre-se de que os scripts do awk são de formato livre. Então ... você poderia fazer isso:

awk 'function isnum(v){if(v~/^[0-9.]+$/)return 1;else return 0;}(NR==1){$4="ratio"}(NR>1&&NF>=3&&isnum($2)&&isnum($3)&&$3>0){$4=($3)/($2)}{print $1"\t"$2"\t"$3"\t"$4}' A  B
    
por 19.04.2016 / 15:12

Tags