【问题标题】:extract columns from multiple .csv files and merge them into one从多个 .csv 文件中提取列并将它们合并为一个
【发布时间】:2017-07-17 10:00:25
【问题描述】:

我有三个文件,我想从中提取一些列并将它们粘贴到一个新文件中。这些文件不一定具有相同的行数。它们按第一列中的值排序。

文件 1 具有以下结构:

col1;col2;col3;col4
SAMPLE-1;1;1;1
SAMPLE-2;1;1;1
SAMPLE-3;1;1;1
SAMPLE-4;1;1;1

此文件由“;”分隔而不是“,”

文件 2 的结构如下:

col5,col6,col7,col8
SAMPLE-1_OTHER_INFO,2,2,2
SAMPLE-2_OTHER_INFO,2,2,2
SAMPLE-3_OTHER_INFO,2,2,2

文件 3 的结构如下:

col9,col10,col11,col12
SAMPLE-1_OTHER_INFO,3,3,3
SAMPLE-2_OTHER_INFO,3,3,3
SAMPLE-3_OTHER_INFO,3,3,3

输出文件 (summary.csv) 应如下所示:

col1,col2,col4,col6,col7,col10,col12
SAMPLE-1,1,1,2,2,3,3
SAMPLE-2,1,1,2,2,3,3
SAMPLE-3,1,1,2,2,3,3
SAMPLE-4,1,1,,,,

基本上所有三个文件的第一列都包含样本标识符。 file1 的 'col1' 应该是输出文件的第一列。然后 col1 中的标识符应与 file2 和 file3 的 col5 和 col9 中的标识符匹配。进行比较时不应考虑“_OTHER_INFO”部分。

如果匹配,则应添加文件 2 和 3 的 col6、col7、col10 和 col12 值的信息。

如果不匹配,则该行仍应在输出文件中,但最后四列应为空(如本例中的“SAMPLE-4”)

我计划使用 awk 或“剪切/粘贴”命令执行此操作。但是我不知道应该如何查找 col1、col5 和 col9 中的值之间的匹配项。

【问题讨论】:

  • 我建议使用一些解释语言,如python 或perl 或ruby。我相信使用 Awk 可以做到这一点,但是使用其中一种语言应该更容易完成这项任务。例如,在 python 中,您可以使用 csv module,它专为此类任务而设计。

标签: bash csv awk


【解决方案1】:

尝试关注,如果这对您有帮助,请告诉我。

awk 'BEGIN{
                FS=";"
          }
     FNR==1{
                f++
           }
     f==1 && FNR>1{
                        a[$1]=$2","$4;
                        next
                   }
     f>1 && FNR==1 {
                        FS=","
                   }
     f==2 && FNR>1{
                        sub(/_.*/,"",$1);
                        b[$1]=$2","$3;
                        next
                }
     f==3 && FNR>1{
                        sub(/_.*/,"",$1);
                        c[$1]=$2","$4;
                        next
                }
     END{
                print "col1,col2,col4,col6,col7,col10,col12";
                for(i in a){
                                printf("%s,%s,%s,%s\n",i,a[i],b[i]?b[i]:",",c[i]?c[i]:",")
                           }
        }
    '     file1 file2 file3

有时间也会尝试添加解释的。

EDIT1:也添加了单行形式的解决方案。

awk 'BEGIN{FS=";"}FNR==1{f++} f==1 && FNR>1{;a[$1]=$2","$4;next} f>1 && FNR==1{FS=","} f==2&&FNR>1{sub(/_.*/,"",$1);b[$1]=$2","$3;next} f==3&&FNR>1{sub(/_.*/,"",$1);c[$1]=$2","$4;next} END{print "col1,col2,col4,col6,col7,col10,col12";for(i in a){printf("%s,%s,%s,%s\n",i,a[i],b[i]?b[i]:",",c[i]?c[i]:",")}}'  file1 file2 file3

【讨论】:

  • 感谢您的解决方案。它工作正常。一件事是结果不会像在 file1 中那样保持原始的行顺序。之后我可以在此列上对课程进行排序,但是这种排序也可以合并到“awk”命令中吗?
  • 我现在遇到了一个问题,即 file2 或 3 包含的行数多于文件 1。在这种情况下,来自 file2 或 file3 的信息不会添加到标准输出中。当 file1 包含比 file2 或 3 更多的行时,没有问题。
【解决方案2】:

sort + sed 技巧(用于已排序的输入文件):

join -t, -j1 -a1 -o1.1,1.2,1.4,2.2,2.3 <(tr ';' ',' < file1) <(sed 's/_[^,]*//g' file2) 
 | join -t, - -a1 -o1.1,1.2,1.3,1.4,1.5,2.2,2.4  <(sed 's/_[^,]*//g' file3)

输出:

SAMPLE-1,1,1,2,2,3,3
SAMPLE-2,1,1,2,2,3,3
SAMPLE-3,1,1,2,2,3,3
SAMPLE-4,1,1,,,,

【讨论】:

    猜你喜欢
    • 2015-02-03
    • 2017-02-15
    • 1970-01-01
    • 2020-12-21
    • 1970-01-01
    • 2016-09-17
    • 2019-10-11
    • 1970-01-01
    相关资源
    最近更新 更多