awk colunas separadas de 3

3

Eu tenho um arquivo que parece com o seguinte (as colunas são separadas por guias e podem conter espaços):

    0637    apple    8528    1392    orange    1390    8528    unknown fruit    7537    1039    banana    1892    0989    pineapple    7537    8528    melon    7537    8528    grape    7537    8528    (null)    (null)

E preciso dividi-lo a cada 3 colunas, cobrindo as que resultarão em [0-9]$ (estou usando awk porque é muito mais rápido que grep em arquivos grandes):

0637    apple    8528
1392    orange    1390
8528    unknown fruit    7537
1039    banana    1892
0989    pineapple    7537
8528    melon    7537
8528    grape    7537

Agora, tenho este comando bonito que faz isso:

awk -F\t '{print $2 "\t" $3 "\t" $4 "\n" $5 "\t" $6 "\t" $7 "\n" $8 "\t" $9 "\t" $10 "\n" $11 "\t" $12 "\t" $13 "\n" $14 "\t" $15 "\t" $16 "\n" $17 "\t" $18 "\t" $19 "\n" $20 "\t" $21 "\t" $22 "\n" $23 "\t" $24 "\t" $25}' filename | awk '/[0-9]$/'

Eu também tenho um comando cut feio que faz o mesmo. Eu ainda estou aprendendo awk, então eu acredito que há uma maneira muito mais sensata de fazer isso. Além disso, posso entrar em problemas se houver mais de $25 . Você pode me ajudar?

    
por Teresa e Junior 04.02.2012 / 08:10

5 respostas

2

Isso funciona:

$ cat splitnum.awk
#!/bin/awk -f
BEGIN {
    FS = OFS = "\t"
}
{
    for ( i = 1; i < NF; i = i + 3) {
        if ( $(i+2) ~ /[0-9]+/ ) {
            print $i, $(i+1), $(i+2)
        }
    }
}
$ awk -f splitnum.awk filename

Ou tudo em uma linha:

awk 'BEGIN{FS=OFS="\t"}{for (i=1;i<NF;i=i+3){if ($(i+2) ~ /[0-9]+/) {print $i, $(i+1), $(i+2)}}}' filename

Basicamente, circulando pelos campos de dados, três de cada vez, verificando se o terceiro é composto de numerais.

    
por 04.02.2012 / 08:26
2

Supondo que os campos estejam separados por uma ou mais guias, e que cada campo possa conter espaços, mas não guias, o seguinte deve funcionar

( IFS=$'\t'; printf '%s %s %s\n' $(<input_file) )

(o subshell é conveniente para não alterar IFS para o shell de chamada).

Como alternativa, se os campos forem separados por um ou mais espaços e tabulações e cada campo não contiver espaços nem tabulações, o seguinte deverá funcionar

printf '%s %s %s\n' $(<input_file)
    
por 04.02.2012 / 09:30
1
awk -F'\t' '{for(i=1;i<=NF;i++)if(!(i%3))$i=$i "\n"}1' file
    
por 04.02.2012 / 08:14
0

Para quem não gosta:

perl -pe 's/(\d+)\s+(\d+)/$1\n$2/g' | 
perl -lnpe 's/^\s*(\d+)\s+([^\d]+?)\s+(\d+).*/$1\t$2\t$3/' |
egrep '[0-9]$'
    
por 04.02.2012 / 08:48
0

Uma resposta perl ainda pior:

perl -pnle 's/\s+/\t/g;s/(\d)\t(\d)/$1\n$2/g;s/^\s+|\s+$//;s/.*[^\d]$//'|grep .
    
por 04.02.2012 / 09:14

Tags