将多个分隔文件中的数据堆叠到一个文件中,并具有可变列

将多个分隔文件中的数据堆叠到一个文件中,并具有可变列

我是脚本新手。遇到 Unix 中的文件合并问题。正在寻找一些方向并偶然发现了这个网站。我看到了很多很棒的帖子和回复,但找不到解决我的问题的方法。非常感谢任何帮助..

我有三个 csv 文件 -> Apex_10_Latest.csv、Apex_20_Latest.csv、Apex_30_Latest.csv。这 3 个文件中的列数各不相同。通常,根据编号,最新文件可能会在末尾附加一些新列。所以我想获取最新的标头并将所有 3 个文件中的数据堆叠到一个新文件 Apex.csv 中。当堆叠旧文件中的数据时,该文件的列数可能少于最新文件的列数,我希望使用适当的分隔符将数据填充为空。

此外,还必须对同一文件夹中的多组文件(每个文件 3 个)递归地完成此操作。 - Apex_10_Latest.csv、Apex_20_Latest.csv、Apex_30_Latest.csv - 合并到 Apex.csv - Code_10_Latest.csv、Code_20_Latest.csv、Code_30_Latest.csv - 合并到 Code.csv - Trans_10_Latest.csv、Trans_20_Latest.csv、Trans_30_Latest.csv - 合并导入 Trans.csv

以下是源文件和预期目标文件的格式...源文件:

  • Apex_30_Latest.csv:
    A B C D
    1,2,3,4
    2,3,4,5
    3,4,5,6

  • Apex_20_Latest.csv:
    甲、乙、丙
    4,5,6
    5,6,7
    6,7,8

  • Apex_10_Latest.csv:
    甲、乙
    7,8
    8,9
    9,10

预期目标文件:

  • Apex.csv
    A B C D
    1,2,3,4
    2,3,4,5
    3,4,5,6
    4,5,6,,
    5,6,7,,
    6,7,8,,
    7,8,,,
    8, 9,,,
    9,10,,,

谢谢...

答案1


与米勒 (http://johnkerl.org/miller/doc/)像往常一样很容易

mlr --csv unsparsify Apex_*_Latest.csv

给你

A,B,C,D
1,2,3,4
2,3,4,5
3,4,5,6
4,5,6,
5,6,7,
6,7,8,
7,8,,
8,9,,
9,10,,

答案2

  cat $(ls -1 Apex_*_Latest.csv | sort -nr -k2 -t'_') | awk -F"," '{
           if (NR==1){
                nfm=NF};
           for (i=1;i<=nfm;i++) {
                printf $i","};
           print ""}' >Apex.csv

您可以sort根据第二个字段 (30,20,10..) 和cat文件反转文件名,以便列数最高的行排在前面。

然后你可以从第一行awk获得最高的列数NFNR if (NR==1){nfm=NF}

然后运行for循环,直到i(列号)大于或等于nfm字段 no 中的打印值,i后跟“,”。如果该字段没有值i(当列少于最新文件时发生),它将只打印,.

答案3

我认为前面的答案是最好的,我只是展示了一种不同的方法,因为我已经很多年没有使用 awk 了,因为 perl 和 python 变得很大。我认为 awk 很好,只是 shell、sed、python 和/或 perl 的混合更适合我的工作。

然而,在这种情况下,我认为任何人都可以看到 awk 解决方案更简洁且更易于阅读。想想看,我想我听说过 awk 被称为命令行电子表格,或者类似的东西。 :-)

根据原始帖子,我选择让 ls 命令按文件修改时间对文件名进行排序,而不是依赖文件名格式。一个是六个,另一个是六个。

因此,为了进行比较,这里有一个高效、可移植、模块化(?!)、纯 shell 版本的解决方案:

    #!/bin/sh

    get_commas() {
        sed 's/[^,]//g; 1q' "$@"
    }

    get_extra_commas() {
        local maxcommas="$1"
        local file="$2"
        local new_commas=$(get_commas "$file")
        local extra_commas=""
        while [ "${new_commas}${extra_commas}" != "${maxcommas}" ]
        do
            extra_commas=",$extra_commas"
        done
        echo "$extra_commas"
    }

    unset header
    ls -t Apex*.csv |
    while read filename
    do
        if [ -z "$header" ]
        then
            header="$(sed 1q "$filename")"
            commas=$(echo "$header" | get_commas)
            echo "$header"
        fi
        extra_commas=$(get_extra_commas $commas "$filename")
        sed "1d; s/\$/$extra_commas/" "$filename"
    done

答案4

这是在中实现的答案磨坊主:

$ cat rect.mlr
for (k,v in $*) {
  @fields[k] = v; # retain already-seen field names
}
for (k,v in @fields) {
  if (isabsent($[k])) {
    $[k] = "";
  }
}

$ mlr --csvlite put -f rect.mlr Apex_30_Latest.csv Apex_20_Latest.csv Apex_10_Latest.csv
A,B,C,D
1,2,3,4
2,3,4,5
3,4,5,6
4,5,6,
5,6,7,
6,7,8,
7,8,,
8,9,,
9,10,,

由于 Miller 本质上处理命名列,因此标题行管理变得更简单。

相关内容