Como reorganizo colunas em um arquivo de texto?

2
Month   Name  Marks  
2016-10 Sam   58  
2016-09 Sam   77  
2016-10 John  64  
2016-09 John  47  
2016-10 Mark  71  
2016-09 Mark  38  
2016-10 Steve 83  
2016-09 Steve 39  

Eu busco esses dados do meu banco de dados com o mês na primeira coluna e marca na terceira coluna de cada aluno na segunda coluna. Agora eu quero editar de tal forma que ele contenha o nome na primeira coluna, marque para 2016-10 na segunda coluna e marque para 2016-09 na terceira coluna.

    
por Vivek Prashar 15.10.2016 / 21:29

4 respostas

3

Supondo que seus dados de entrada estejam em um arquivo chamado "notas", tente:

$ awk 'BEGIN{ PROCINFO["sorted_in"]="@ind_str_desc"} NR==1{next} {m[$1]; n[$2]; g[$2,$1]=$3} END{for (name in n) {printf "%s",name; for (month in m) printf " %s",g[name,month]; print""}}' grades | column -t
Steve  83  39
Sam    58  77
Mark   71  38
John   64  47

A saída tem uma linha por aluno com as notas apresentadas em ordem decrescente de mês.

Para aqueles que preferem o código espalhado por várias linhas:

gawk '
    BEGIN{ PROCINFO["sorted_in"]="@ind_str_desc"}
    NR==1{
        next
    }

    {
        m[$1]
        n[$2]
        g[$2,$1]=$3
    }

    END{
        for (name in n) {
            printf "%s",name
            for (month in m)
                printf " %s", g[name,month]
                print""
        }
    }

    ' grades | column -t

Como funciona

  • BEGIN{ PROCINFO["sorted_in"]="@ind_str_desc"}

    Isto diz ao awk que queremos matrizes ordenadas em índices. Este é um recurso do GNU.

  • NR==1{next}

    Isso diz ao awk para pular a primeira linha. Se você quiser adicionar um cabeçalho para o arquivo de saída, poderíamos fazê-lo aqui.

  • m[$1]

    Isso diz ao awk para adicionar uma entrada para o mês atual na matriz associativa m . Não precisamos atribuir um valor porque simplesmente usaremos isso para rastrear quais meses estão presentes na entrada.

  • n[$2]

    Isto diz ao awk para adicionar uma entrada para o nome do aluno no array associativo n . Não precisamos atribuir um valor porque simplesmente usaremos isso para rastrear quais meses estão presentes na entrada.

  • g[$2,$1]=$3

    Isso atribui a nota como o valor sob a chave do nome do aluno, mês na matriz associativa g .

  • END{for (name in n) {printf "%s",name; for (month in m) printf " %s",g[name,month]; print""}}

    Depois de chegarmos ao final do arquivo, imprimimos todos os nomes e notas para cada aluno.

  • column -t

    Este passo opcional torna a saída bonita.

por 15.10.2016 / 22:05
0

Se você precisar de um mês duplo

sed '
    2~2{                                               #for even lines
        N                                              #attach next line
        s/\(\S\+ \)\(\S\+ \)[0-9]*\n\(\S\+\).*// #rearrange two line
    }
    1c\Name Month1 Month2                              #output new header
    ' file.data

Ou marcas duplas

sed '
    1!N             #from second line attach next line 
    s/\S\+ //       #remove first field (2016-10)
    s/\n.* / /      #remove 2 fields in attached line
    t               #ommit 1st line
    s/$/1 Marks2/   #arrange header
    ' file.data

Outra versão

echo 'Name Marks1 Marks2' ;\
paste -sd' \n' <(tail -n +2 file.data) |
cut -d' ' -f 2,3,6
    
por 15.10.2016 / 22:25
0

Um exemplo um pouco bruto:

Aqui você define a variável m para as datas que deseja incluir e seu pedido; como uma string separada por vírgulas. Conforme o exemplo abaixo, seria:

m=2016-10,2016-09

Que por sua vez dá:

Name 2016-10 2016-09

Isso requer que os nomes sejam exclusivos e sem espaços…

awk -v m=2016-10,2016-09 '
    NR==1{next}
    {
        # Set array x[name][month]=marks
        x[$2][$1]=$3
    }
    END {
        split(m, k, ",")
        printf "Name"
        for (v in k)
            printf "\t%s", k[v]
        for (e in x) {
            printf "\n%s", e
            for (v in k)
                printf "\t%s", x[e][k[v]]
        }
        print ""
    }
' data

Exemplo de saída:

Name    2016-10 2016-09
Steve   83  39
Mark    71  38
John    64  47
Sam 58  77

Por column -t :

Name   2016-10  2016-09
Steve  83       39
Mark   71       38
John   64       47
Sam    58       77

Se esta é uma coisa de uma vez, e seus dados são como por exemplo (ordenados, apenas dois meses, etc.), então isso também poderia ser feito:

awk 'NR==1{next}NR%2{print $3;next}{printf "%s\t%s\t",$2,$3}' data
    
por 16.10.2016 / 01:53
-1

Você pode tentar

awk '{print $2, $3, $1}' filename
    
por 15.10.2018 / 15:11