Número de campos separados por vírgulas em um arquivo de texto

6

Estou tentando criar uma instrução awk para ler este arquivo:

A   1,2,3   *
A   4,5,6   **
B   1
B   4,5     *

e crie um arquivo como este:

A   1,2,3   *    3   1   0.333
A   4,5,6   **   3   2   0.666
B   1            1   0   0
B   4,5     *    2   1   0.5

Neste novo arquivo, as três primeiras colunas são as mesmas que no arquivo original. A quarta coluna deve conter o número de elementos separados por vírgulas na coluna 2. A quinta coluna deve conter o número de caracteres na coluna 3. A última coluna contém a proporção da coluna 5 na coluna 4 (ou seja, coluna 5 dividida pela coluna 4 ).

Estou tentando o seguinte código:

awk '{print $1"\t"$2"\t"$3"\t"(NF","$2 -1)"\t"length($3)"\t"(length($3)/(NF","$2-1))}' file1 > file2

Mas recebi a seguinte saída:

A   1,2,3   *    3,0   1   0.333333
A   4,5,6   **   3,3   2   0.666667
B   1            2,0   0   0
B   4,5     *    3,3   1   0.333333

Não consigo descobrir o que estou fazendo de errado na coluna 4.

    
por dovah 17.07.2014 / 13:47

2 respostas

6

Você parece esperar que (NF","$2 -1) seja tratado como uma função que retornará o número de elementos delimitados por vírgula no campo $2 - não. NF é sempre o número de campos no registro .

Em vez disso, você pode usar split function split($2,a,",") do awk, que divide o campo $2 em uma matriz a e retorna o número de elementos. Você também pode arrumar o código usando o separador de arquivo de saída para tab em vez de usar "\ t" explícito em sua declaração de impressão

awk '{l2=split($2,a,","); OFS="\t"; print $1, $2, $3, l2, length($3), length($3)/l2}' file1
    
por 17.07.2014 / 14:06
3

Aqui está uma abordagem de Perl:

$ perl -lane '@k=($F[1]=~/,/g); $i=$#k+2; $l=length($F[2]); 
              print "@F $i $l ", $l/$i' file 
A 1,2,3 * 3 1 0.333333333333333
A 4,5,6 ** 3 2 0.666666666666667
B 1 1  0
B 4,5 * 2 1 0.5

Ou, com printf para uma bela formatação:

$ perl -lane '@k=($F[1]=~/,/g); $i=$#k+2; $l=length($F[2]); 
              printf "%s %-5s %-3s %s %3s %10f\n",@F,$i,$l,$l/$i' file 
A 1,2,3 *   3   1   0.333333
A 4,5,6 **  3   2   0.666667
B 1     1      0   0.000000
B 4,5   *   2   1   0.500000

Explicação

  • -lane : o -l remove as novas linhas à direita de cada linha de entrada; o -a divide automaticamente cada linha de entrada na matriz @F no espaço em branco; o -n significa "leia o arquivo de entrada linha por linha" e o -e permite passar um script como um parâmetro de linha de comando.
  • @k=($F[1]=~/,/g); $i=$#k+2; : a matriz @k contém todas as vírgulas encontradas no segundo campo. Então, $i está definido para o maior índice é @F ( $#F ) mais dois. O sinal de adição 2 é necessário porque i) os arrays são contados a partir de 0, então o maior índice de um array de um único elemento será 0. Estamos contando vírgulas, não valores, então precisamos adicionar mais um, pois 1,2 tem dois valores mas apenas uma vírgula.
  • $l=length($F[2]); : $l agora é o número de caracteres do campo 3d.
  • print "@F $i $l ", $l/$i : imprime as informações solicitadas. @F é a linha do arquivo de entrada e o resto é o que você pediu.
por 17.07.2014 / 15:12