Como subtrair linhas da primeira linha usando o awk?

1

Meu arquivo de dados se parece com:

10 -0.314690785295
20 -0.251967909317
30 -0.215271387106
40 -0.189228416217

A saída desejada é:

10 -0.0627229
20 -0.0994193
30 -0.1254623

Eu sou realmente novo no bash, então qualquer ajuda com relação a essa pergunta estúpida seria de grande ajuda.

    
por baban 09.02.2016 / 21:04

1 resposta

3
  awk 'BEGIN {first_row = 0; col_val=""}{ if (first_row == 0) {first_row = $2; col_val=$1} else {print col_val " " first_row - $2; col_val=$1}}'

Esta é a saída da linha de comando:

 $ echo "10 -0.314690785295
 20 -0.251967909317
 30 -0.215271387106
 40 -0.189228416217" | awk 'BEGIN {first_row = 0; col_val=""}{ if (first_row == 0) {first_row = $2; col_val=$1} else {print col_val " " first_row - $2; col_val=$1}}'
 10 -0.0627229
 20 -0.0994194
 30 -0.125462

Ok, agora, por que isso funciona:

A cláusula BEGIN define uma seção de código executada como inicialização antes de iniciar. Neste local, inicializamos as duas variáveis que vamos acompanhar para o resto da lógica.

Na parte principal do programa, no segundo conjunto de {}. nós definimos a lógica que será executada para cada linha na entrada (você também pode prefixar um padrão para ser executado apenas em algumas linhas, mas que esteja fora do escopo desta resposta).

A lógica testa se o valor first_row está definido. Se não for, então esta é a primeira linha da entrada, e só precisamos inicializar o valor first_row para ser o segundo sting na linha que é $ 2, também precisamos copiar a string que estava na primeira coluna $ 1 para corresponder à sua saída desejada, copiamos esse valor em col_val.

Else, que é toda outra linha na entrada, nós imprimimos o col_value um espaço e o resultado da subtração do first_row com o valor na linha atual na segunda posição $ 2 assim first_row - $ 2. Em seguida, copiamos o novo valor da string na primeira coluna da entrada em col_val.

Eu não entendi o que você realmente precisava na primeira vez :) .. Este é o script awk que fará o que você quer .. porque 10 - 20 é -10 não 10.

 awk '{ if (NR == 1) { for (i = 1; i <= NF; i++){ first_row[i] = $i} } else { for (i = 1; i <= NF; i++){ printf "%s ", first_row[i] - $i }; printf "\n"}}'

Observe que a saída parece com isso, o que é um pouco diferente do que você esperava para a primeira coluna. Adicionei outra coluna para mostrar a progressão.

 echo "10 -0.314690785295 18
 20 -0.251967909317 12
 30 -0.215271387106 35
 40 -0.189228416217 44" | awk '{ if (NR == 1) { for (i = 1; i <= NF; i++){first_row[i] = $i} } else { for (i = 1; i <= NF; i++){ printf "%s ", first_row[i] - $i }; printf "\n"}}'
 -10 -0.0627229 6 
 -20 -0.0994194 -17 
 -30 -0.125462 -26 
    
por 09.02.2016 / 21:16