在Linux上使用列名=文件名将多个文件中的列添加到新文件中

时间:2018-11-26 10:51:13

标签: linux bash unix awk sed

我有多个文件扩展名为.profile的6列。每个文件的前3列相同。我想让输出文件包含前3个(相似)列,然后从每个文件附加第六列。附加到输出文件的列的名称应与输入文件的名称相同。输入文件如下:

 FID       IID  PHENO    CNT   CNT2    SCORE
  00010   0001002      2     12      2 -0.00285
  00017   0001702      2     12      2 -0.00285

另一个输入文件看起来像这样

FID       IID  PHENO    CNT   CNT2    SCORE
  00010   0001002      2     28      9 -0.00843036
  00017   0001702      2     28      9 0.00710286

这两个文件的名称分别是“ Artery_Aorta.ENSG00000000460.12.wgt.RDat.txt.profile”和“ Artery_Aorta.ENSG00000000971.11.wgt.RDat.txt.profile”。我希望我的输出文件看起来像

FID       IID  PHENO  ENSG00000000460.12  ENSG00000000971.11
  00010   0001002    2   -0.00285   -0.00843036
  00017   0001702    2   -0.00285     0.00710286

到目前为止,我已经尝试过

paste *.profile | awk '{print $1, $2, $3, $6, $6 + 6}'

但是输出不是期望的。它会将$ 6中的值加6。但是,我想在输出文件中打印每第六列并附加前几列。输出文件如下所示

FID IID PHENO SCORE 6
00010 0001002 2 -0.00843036 5.99157
00017 0001702 2 0.00710286 6.0071

有人可以帮我吗?

2 个答案:

答案 0 :(得分:1)

AWK解决方案,如果您需要在每个输入文件中添加第六列并按输入进行排序:

awk '
(NR==FNR) { arro[++order]=$1 FS $2 FS $3; arr[$1 FS $2 FS $3]=$6; }
(NR!=FNR) { arr[$1 FS $2 FS $3]=arr[$1 FS $2 FS $3] FS $6; }
END { for (i=1;i<=order;i++) print(arro[i] FS arr[arro[i]]); }
' *.profile

输出:

FID IID PHENO SCORE SCORE
00010 0001002 2 -0.00285 -0.00843036
00017 0001702 2 -0.00285 0.00710286

输入:

$ ls *.profile
Artery_Aorta.ENSG00000000460.12.wgt.RDat.txt.profile  Artery_Aorta.ENSG00000000971.11.wgt.RDat.txt.profile

这里的每个评论请求都是将添加的列替换为文件名子字符串的解决方案:

awk '
(FNR==1) {match(FILENAME,/ENSG[0-9]+\.[0-9]+/); $6=substr(FILENAME,RSTART,RLENGTH);}
(NR==FNR) { arro[++order]=$1 FS $2 FS $3; arr[$1 FS $2 FS $3]=$6; }
(NR!=FNR) { arr[$1 FS $2 FS $3]=arr[$1 FS $2 FS $3] FS $6; }
END { for (i=1;i<=order;i++) print(arro[i] FS arr[arro[i]]); }
' *.profile

输出:

FID IID PHENO ENSG00000000460.12 ENSG00000000971.11
00010 0001002 2 -0.00285 -0.00843036
00017 0001702 2 -0.00285 0.00710286

答案 1 :(得分:1)

假设输入文件用制表符分隔,并且第一列前面没有这些前导空格,则以下脚本将生成预期的输出:

#! /bin/bash
merge() {
    cols=$(seq -s, 6 6 $(("$#" * 6)))
    header=$(grep -o 'ENSG[0-9]*.[0-9]*' <<< "$*" | paste -s)
    paste "$@" | cut -f1-3,"$cols" | sed "1s/SCORE.*/$header/"
}
merge Artery_Aorta.*