Conversión de un archivo de datos de 2 columnas a formato de fila

Conversión de un archivo de datos de 2 columnas a formato de fila

Soy un usuario principiante de Unix y estoy intentando convertir un archivo que tiene 2 columnas en un archivo de datos con formato de fila.

Archivo de datos de muestra: HEADER Count: 6, EMPID, EMPNAME,SALARY,DEPT,AGE,JOD

col1;col2

empid;1001
empname;ABC
salary;3000
dept;ABC
age;24
JOD;20170101
empid;2001
salary;5000
dept;XYZ
age;27
JOD;20170303
empid;1002
empname;MAN
salary;11000
dept;SCI
age;30
JOD;20180607
empid;1005
empname;NAME
salary;10200
dept;XYZ
JOD;20161212

A continuación se muestra el código que probé, pero no obtengo el resultado deseado.

awk '
BEGIN {FS=';'
       OFS=';'
       RS="\n"
Print An = "empid", Bn = "empname", Cn = "salary", Dn = "Dept", En = "age", Fn = "DOJ"
     }
     {
     A=B=C=D=E=F=" "
     for ( i = 1; i<=NF; i++)
          {
           if($i == An)
                A = $(i+1)
           if($i == Bn)
                B = $(i+1)
           if($i == Cn)
                C = $(i+1)
           if($i == Dn)
                D = $(i+1)
           if($i == En)
                E = $(i+1)
           if($i == Fn)
                F = $(i+1)
             }
            print A, B, C, D, E, F
             }' FILE.txt >New_file.txt

avíseme si se requiere algo de mi parte. Estoy usando PUTTY para Unix, CPU Intel Core i5-5300U de 64 bits, 2,30 GHz.

¿Podrías ayudarme con esto? Sería de gran ayuda.

Saludos, Naresh

Respuesta1

Dado que no tiene una cantidad constante de campos en cada registro de entrada, se requiere un enfoque de 2 pasos para evitar tener que codificar los nombres de las columnas en su código:

$ cat tst.awk
BEGIN { FS=OFS=";" }
NR==FNR {
    if ( !($1 in colNrs) ) {
        colNrs[$1] = ++numCols
        hdr = (numCols>1 ? hdr OFS : "") $1
    }
    next
}
FNR == 1 { print hdr }
{ colNr = colNrs[$1] }
colNr in vals { prt() }
{ vals[colNr] = $2 }
END { prt() }

function prt(   colNr) {
    for (colNr=1; colNr<=numCols; colNr++) {
        printf "%s%s", vals[colNr], (colNr<numCols ? OFS : ORS)
    }
    delete vals
}

.

$ awk -f tst.awk file file
empid;empname;salary;dept;age;JOD
1001;ABC;3000;ABC;24;20170101
2001;;5000;XYZ;27;20170303
1002;MAN;11000;SCI;30;20180607
1005;NAME;10200;XYZ;;20161212

Para utilizar el script awk anterior en un script de shell:

#!/bin/env bash

... other shell stuff ...

awk '
BEGIN { FS=OFS=";" }
NR==FNR {
    if ( !($1 in colNrs) ) {
        colNrs[$1] = ++numCols
        hdr = (numCols>1 ? hdr OFS : "") $1
    }
    next
}
FNR == 1 { print hdr }
{ colNr = colNrs[$1] }
colNr in vals { prt() }
{ vals[colNr] = $2 }
END { prt() }

function prt(   colNr) {
    for (colNr=1; colNr<=numCols; colNr++) {
        printf "%s%s", vals[colNr], (colNr<numCols ? OFS : ORS)
    }
    delete vals
}
' file file

... other shell stuff ...

Respuesta2

En primer lugar, hay errores de sintaxis en su código.

Las comillas simples en tu BEGINbloque deben ser dobles.

BEGIN {FS=";";
       OFS=";";
       RS="\n";

En segundo lugar, no puede asignar variables e imprimir de la forma en que lo ha hecho y esto necesita corrección.

En tercer lugar, Dn = "Fecha" y el campo en sus registros es "fecha" y tiene el mismo problema con "DOJ"/"JOD"

        An = "empid"; Bn = "empname"; Cn = "salary"; Dn = "dept"; En = "age"; Fn = "JOD";
        print An, Bn, Cn, Dn, En, Fn
     }

Estas correcciones al BEGINbloque te llevan a...

empid;empname;salary;dept;age;JOD
1001; ; ; ; ; 
 ;ABC; ; ; ; 
 ; ;3000; ; ; 
 ; ; ;ABC; ; 
 ; ; ; ;24; 
 ; ; ; ; ;20170101
2001; ; ; ; ; 
 ; ;5000; ; ; 
 ; ; ;XYZ; ; 
 ; ; ; ;27; 
 ; ; ; ; ;20170303
1002; ; ; ; ; 
 ;MAN; ; ; ; 
 ; ;11000; ; ; 
 ; ; ;SCI; ; 
 ; ; ; ;30; 
 ; ; ; ; ;20180607
1005; ; ; ; ; 
 ;NAME; ; ; ; 
 ; ;10200; ; ; 
 ; ; ;XYZ; ; 
 ; ; ; ; ;20161212

Lo cual se debe a errores lógicos.

Como señala @pLumo, faltan campos de datos en sus conjuntos de datos y su código no lo permite, pero más aún, awkse imprime en cada registro (cada línea) y no en cada conjunto de registros (justo antes de que aparezca empid).

Hay muchas maneras de despellejar a este gato en particular, pero como hoy estoy de buen humor, aquí hay una sencilla para que un principiante aprenda a hacer arreglos....

En el BEGINbloque, cargue una matriz con los números de campo que desee utilizando los nombres de los campos como índices e imprima los títulos.

awk -F";" 'BEGIN{
    fields["empid"]=1;
    fields["empname"]=2;
    fields["salary"]=3;
    fields["dept"]=4;
    fields["age"]=5;
    fields["JOD"]=6;
    print "empid;empname;salary;dept;age;JOD"
    }

si el primer campo es "empid" y &&no es el primer registro NR>1, entonces repita la matriz que contendrá los valores de su campo (la matriz está vacía cuando NR==1es por eso que la omitimos) y después de haber impreso la matriz, vacíela para reutilizar pordelete

    $1=="empid" && NR>1 {
         for (f=1; f<6; f++) printf field[f]";"; print field[6]; delete field}

Para cada línea del archivo, cargue el valor $2en su matriz de valores fieldusando el número de campo recuperado de la fieldsmatriz que construimos en el BEGINbloque como índice, según el nombre del campo en$1

   {field[fields[$1]]=$2

La matriz seguirá cargada con valores no impresos cuando llegue al final del archivo, por lo que tendrá que imprimir la matriz por última vez.

    }END{for (f=1; f<6; f++) printf field[f]";"; print field[6]}' file1

Editar

Con este script copie/pegue en la terminal

awk -F";" 'BEGIN{
    fields["empid"]=1;
    fields["empname"]=2;
    fields["salary"]=3;
    fields["dept"]=4;
    fields["age"]=5;
    fields["JOD"]=6;
    print "empid;empname;salary;dept;age;JOD"
    }$1=="empid" && NR>1 {
         for (f=1; f<6; f++) printf field[f]";"; print field[6]; delete field}{field[fields[$1]]=$2 
         }END{for (f=1; f<6; f++) printf field[f]";"; print field[6]}' file1

Con esta entrada

empid;1001
empname;ABC
salary;3000
dept;ABC
age;24
JOD;20170101
empid;2001
salary;5000
dept;XYZ
age;27
JOD;20170303
empid;1002
empname;MAN
salary;11000
dept;SCI
age;30
JOD;20180607
empid;1005
empname;NAME
salary;10200
dept;XYZ
JOD;20161212

La salida es

empid;empname;salary;dept;age;JOD
1001;ABC;3000;ABC;24;20170101
2001;;5000;XYZ;27;20170303
1002;MAN;11000;SCI;30;20180607
1005;NAME;10200;XYZ;;20161212 

información relacionada