2017-07-17 219 views
1

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

文件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值的信息。

如果没有比赛,该行仍然应该在输出文件,但最后四列应该是空的(如在这种情况下,“样品4”)

我正打算执行此操作用awk或'cut/paste'命令。但是我不知道我应该如何寻找col1,col5和col9中的值之间的匹配。

+0

我会建议使用一些解释的langauge像[蟒](https://stackoverflow.com/q (https://stackoverflow.com/questions/tagged/perl)或[ruby](https://stackoverflow.com/questions/tagged/ruby)。我相信Awk会有这种可能,使用这种语言之一应该会更容易。例如,在python中你可以使用[csv module](https://docs.python.org/2/library/csv.html),这是专门为这样的任务设计的。 –

回答

2

请尝试下面,让我知道这是否有助于你。

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 

在某个时候也会尝试添加说明。

编辑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 
+0

感谢您的解决方案。它工作正常。有一件事是,结果并没有像file1那样保持行的原始顺序。我可以在此专栏之后排除课程,但是这种排序也可以包含在'awk'命令中吗? – user1987607

+0

当file2或3包含比文件1多的行时,我遇到了一个问题。在这种情况下,来自file2或file3的信息不会添加到标准输出中。当file1包含更多的文件2或3行时,没有问题。 – user1987607

0

排序 + 的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,,,, 
相关问题