【问题标题】:Adding columns from multiple files to the new file with column name = file name on Linux在 Linux 上使用列名 = 文件名将多个文件中的列添加到新文件中
【发布时间】:2018-11-27 15:32:04
【问题描述】:

我有多个具有 .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

谁能帮我解决这个问题?

【问题讨论】:

    标签: linux bash unix awk sed


    【解决方案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.*
    

    【讨论】:

      【解决方案2】:

      如果您需要从每个输入文件中添加第 6 列并按您的输入排序,则使用 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
      

      【讨论】:

      • 谢谢。这是有效的,但我需要以 ENSG 开头的文件名部分后跟数字(例如,ENSG00000000460.12)作为输出文件中的列名:(如果可能的话,你能解释一下代码吗?
      • 我在答案中添加了重命名的列解决方案。第一个文件的说明(NR==FNR)我正在创建关联数组,每列 1、2、3 具有索引,并为其分配第 6 列的值。每个其他文件(NR!= FNR)另外添加第 6 列作为下一个列等。最后按订单打印数组以保持与输入相同的顺序。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-03
      • 2017-06-08
      • 2023-03-13
      • 1970-01-01
      • 2018-02-28
      相关资源
      最近更新 更多