使用awk从带有标题的CSV文件创建表

使用awk从带有标题的CSV文件创建表,csv,awk,tableheader,Csv,Awk,Tableheader,我有一个以逗号分隔的CSV文件,带有标题,希望将它们包含在表中 输入: header,word1,word2,word3 supercalifragi,black,white,red adc,bad,cat,love 输出: | header | word1 | word2 | word3 | | -------------- | ----- | ----- | ----- | | supercalifragi | black | white | red | | adc

我有一个以逗号分隔的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() 
}

``

我可以自由地重写整个代码,避免出现划痕。这应该起作用:

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
    }

}

或者,您可以使用FS=,但这实际上仅限于您的示例。

一个较短的双扫描选项

$ 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  |
这不完全是您要求的输出,但也许这就是您真正需要的:

$ column -t -s, -o' | ' < file | awk '1; NR==1{gsub(/[^|]/,"-"); print}'
header         | word1 | word2 | word3
---------------|-------|-------|------
supercalifragi | black | white | red
adc            | bad   | cat   | love

一些想法。您不需要在这里用分号终止FS,of。此外,OFS将打印两个管道,而不是一个或应该:逗号代表OFS。printf\n如果需要返回回车符,则应为print。不过,它不会打印您想要的输出。最后,NR=1:no。代码的这一部分是针对所有记录执行的,因此它从NR=1开始,然后是NR=2、NR=3,依此类推。您可能希望阅读较短的备选方案如何使用awk脚本而不是直接从命令行实现?要使脚本将单引号之间的内容复制到文件并使用awk-f script.name运行。。。如果您有特定的问题,我可以回答,但您首先需要付出一些努力。我在运行文件时遇到的问题是文件{,}。这是干什么用的。这是用来指定我使用的文件吗?可读性稍差一点,但是如果你想要一个较短的代码,这非常好。如果你不想在第二步添加管道,我想是的。我记不太清楚markdown表是如何工作的:他们是否需要在|--|中的管道附近使用空格?对于更高级的用户,一定要检查这个答案。
$ column -t -s, -o' | ' < file | awk '1; NR==1{gsub(/[^|]/,"-"); print}'
header         | word1 | word2 | word3
---------------|-------|-------|------
supercalifragi | black | white | red
adc            | bad   | cat   | love