Преобразование файла данных с 2 столбцами в формат строки

Просто добавлю свой опыт в эту тему. Я конвертирую старую машину Asus P5G41T -MLX для запуска FreeBSD 11.1. Изначально он не мог найти устройство Atheros AR8131 -BL1A. Обновление BIOS решило проблему

.
1
06.04.2020, 17:20
2 ответа

Поскольку у вас нет постоянного количества полей в каждой входной записи, требуется двухпроходный -подход, чтобы избежать использования жестких -имен столбцов кода в вашем коде:

$ 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

Чтобы использовать приведенный выше awk-скрипт в сценарии оболочки:

#!/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...
0
28.04.2021, 23:18

Во-первых, в вашем коде есть синтаксические ошибки.

Одинарные кавычки в блоке BEGINдолжны быть двойными

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

Во-вторых, вы не можете назначать переменные и печатать так, как вы это сделали, и это требует исправления.

В-третьих, Dn = «Дата», а поле в ваших записях — «дата», и у вас такая же проблема с «DOJ»/«JOD»

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

Эти исправления в блоке BEGINприводят к...

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

Это из-за логических ошибок.

Как указывает @pLumo, в ваших наборах данных отсутствуют поля данных, и ваш код не позволяет этого, кроме того, awkпечатается в каждой записи (в каждой строке ), а не в каждом наборе записей (непосредственно перед появлениемempid).

Есть много способов снять шкуру с этого конкретного кота, но, поскольку я сегодня в хорошем настроении, вот простой способ, которому может следовать новичок, изучающий массивы....

В блоке BEGINзагрузите массив с номерами полей, которые вы хотите использовать, используя имена полей в качестве индексов, и распечатайте заголовки

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"
    }

если первое поле "empid" и &&это не первая запись NR>1затем перебрать массив, который будет содержать значения ваших полей (массив пуст, когда NR==1вот почему мы пропустите его )и после того, как вы распечатаете массив, очистите его для повторного использования с помощьюdelete

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

Для каждой строки в файле загрузите значение $2в свой массив значений field, используя номер поля, восстановленный из массива fields, который мы создали в блоке BEGIN, в качестве индекса на основе имя поля в$1

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

Когда вы дойдете до конца файла, массив по-прежнему будет загружаться с нераспечатанными значениями, поэтому вам придется распечатать массив в последний раз

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

Редактировать

С помощью этого скрипта скопируйте/вставьте в терминал

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

С этим входом

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

Выход

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 
0
28.04.2021, 23:18

Теги

Похожие вопросы