создание таблицы из файла CSV с заголовками с помощью awk

У меня есть CSV-файл с заголовками, разделенными запятыми, и я хочу включить их в таблицу.

Вход:

header,word1,word2,word3
supercalifragi,black,white,red
adc,bad,cat,love

Выход:

| header         | word1 | word2 | word3 |
| -------------- | ----- | ----- | ----- |
| supercalifragi | black | white | red   |
| adc            | bad   | cat   | love  |

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

Вот обновленный код:

function pr(){
    for(i=1;i<=NF;i++)
        printf "| %-"len[i]+1"s",$i;
    printf "|\n"
}
NR==FNR{
    for(i=1;i<=NF;i++)
        if(len[i]<length($i)){
            len[i]=length($i);
            word[i]=$i
        }next 
}{pr()}
FNR==1{
    for(i=1;i<=NF;i++){
        gsub(/./,"-",word[i]);
        $i=word[i]};
    pr() 
}

``


person student    schedule 19.04.2018    source источник
comment
Некоторые мысли. Здесь не нужно заканчивать FS, OFS точкой с запятой. Кроме того, это , OFS напечатает две трубы вместо одной (или должно): запятая означает OFS. printf "\n" должно читаться как print "", если вам нужна обратная перевозка. Однако он не напечатает желаемый результат. Наконец, #NR=1: нет. Эта часть вашего кода выполняется для всех записей, поэтому она начинается с NR=1, затем NR=2, NR=3 и так далее. Вы можете прочитать руководство.   -  person Daemon Painter    schedule 20.04.2018


Ответы (3)


Я взял на себя смелость переписать весь код с нуля. Это должно работать:

BEGIN {
    FS=","
    OFS=" | "
    for (i=1; i<=NF; i++) {
        transientLength[i] = 0
    }
}

{
    if(NR==1) {
    # read headers
        for (i=0; i<NF; i++) {
            headers[i] = $(i+1)
            transientLength[i] = (length($(i+1))>=transientLength[i] ? length($(i+1)) : transientLength[i])
        }
    } else {
        for (i=0; i<NF; i++) {
            fields[NR][i] = $(i+1)
            transientLength[i] = (length($(i+1))>=transientLength[i] ? length($(i+1)) : transientLength[i])
        }
    }
}

END {
    # print header
    for (j in headers) {
        spaceLength = transientLength[j]-length(headers[j])
        for (s=1;s<=spaceLength;s++) {
            spaces = spaces" "
        }
        if (!printable) printable = headers[j] spaces
        else printable = printable OFS headers[j] spaces
        spaces = ""     # garbage collection
    }
    printable = "| "printable" |"
    print printable
    printable = ""      # garbage collection
    # print alignments
    for (j in transientLength) {
        for (i=1;i<=transientLength[j];i++) {
            sep = sep"-"
        }
        if (!printable) printable = sep
        else printable = printable OFS sep
        sep = ""        # garbage collection
    }
    printable = "| "printable" |"
    print printable
    printable = ""      # garbage collection
    # print all rows
    for (f in fields) {
        for (j in fields[f]) {
            spaceLength = transientLength[j]-length(fields[f][j])
            for (s=1;s<=spaceLength;s++) {
                spaces = spaces" "
            }
            if (!printable) printable = fields[f][j] spaces
            else printable = printable OFS fields[f][j] spaces
            spaces = ""     # garbage collection
        }
        printable = "| "printable" |"
        print printable
        printable = ""      # garbage collection
    }

}

Но имейте в виду: вам нужно очистить входной файл от ненужных пробелов. Следует читать:

header,word1,word2,word3
supercalifragi,black,white,red
adc,bad,cat,love

В качестве альтернативы вы можете использовать FS=", ", но на самом деле это будет ограничено вашим примером.

person Daemon Painter    schedule 20.04.2018
comment
Обязательно проверьте это другое ответ также, для более продвинутых пользователей. - person Daemon Painter; 24.04.2018

более короткая альтернатива с двойным сканированием

$ awk -F' *, *' 'function pr() 
                 {for(i=1;i<=NF;i++) printf "| %-"len[i]+1"s",$i; printf "|\n"}

          NR==FNR{for(i=1;i<=NF;i++) 
                    if(len[i]<length($i)) {len[i]=length($i); word[i]=$i} next}

                 {pr()}

           FNR==1{for(i=1;i<=NF;i++) {gsub(/./,"-",word[i]); $i=word[i]}; pr()}'  file{,}

| header         | word1 | word2 | word3 |
| -------------- | ----- | ----- | ----- |
| supercalifragi | black | white | red   |
| adc            | bad   | cat   | love  |
person karakfa    schedule 20.04.2018
comment
более короткая альтернатива, как это реализовать с помощью сценария awk, а не напрямую из командной строки? - person student; 21.04.2018
comment
чтобы создать сценарий, скопируйте содержимое между одинарными кавычками в файл и запустите с помощью awk -f script.name ... Если у вас есть конкретные вопросы, я могу ответить, но сначала вам нужно приложить некоторые усилия. - person karakfa; 22.04.2018
comment
проблема, с которой я столкнулся при запуске файла, была связана с файлом {,}. для чего это. это для того, чтобы указать, какой файл я использую? - person student; 23.04.2018
comment
Немного менее читабельно, но очень удобно, если вам нужен более короткий код. - person Daemon Painter; 24.04.2018

Это не точно результат, который вы просили, но, возможно, это все, что вам действительно нужно:

$ column -t -s, -o' | ' < file | awk '1; NR==1{gsub(/[^|]/,"-"); print}'
header         | word1 | word2 | word3
---------------|-------|-------|------
supercalifragi | black | white | red
adc            | bad   | cat   | love
person Ed Morton    schedule 22.04.2018
comment
Думаю, да, если вы не удосужились добавить трубы на втором этапе. Я плохо помню, как работает таблица уценки: нужен ли пробел возле трубы в |---|? - person Daemon Painter; 24.04.2018