使用AWK将列附加到制表符分隔的文件

使用AWK将列附加到制表符分隔的文件,awk,tab-delimited,Awk,Tab Delimited,我有多个没有标题的文件,前四列相同,第五列不同。我必须使用awk将前四个公共列(所有第五列都有各自的标题)附加到单个最终制表符分隔的文本文件中,如下所示 文件1.txt chr1 101845021 101845132 A 0 chr2 128205033 128205154 B 0 chr3 128205112 128205223 C 0 chr4 36259133 36259244 D 0 chr5 36259

我有多个没有标题的文件,前四列相同,第五列不同。我必须使用awk将前四个公共列(所有第五列都有各自的标题)附加到单个最终制表符分隔的文本文件中,如下所示

文件1.txt

chr1    101845021   101845132   A   0
chr2    128205033   128205154   B   0
chr3    128205112   128205223   C   0
chr4    36259133    36259244    D   0
chr5    36259333    36259444    E   0
chr6    25497759    25497870    F   1
chr7    25497819    25497930    G   1
chr8    25497869    25497980    H   1
文件2.txt

chr1    101845021   101845132   A   6
chr2    128205033   128205154   B   7
chr3    128205112   128205223   C   7
chr4    36259133    36259244    D   7
chr5    36259333    36259444    E   10
chr6    25497759    25497870    F   11
chr7    25497819    25497930    G   11
chr8    25497869    25497980    H   12
文件3.txt

chr1    101845021   101845132   A   41
chr2    128205033   128205154   B   41
chr3    128205112   128205223   C   42
chr4    36259133    36259244    D   43
chr5    36259333    36259444    E   47
chr6    25497759    25497870    F   48
chr7    25497819    25497930    G   48
chr8    25497869    25497980    H   49
预期输出文件Final.txt

Part    Start   End Name    File1   File2   File3
chr1    101845021   101845132   A   0   6   41
chr2    128205033   128205154   B   0   7   41
chr3    128205112   128205223   C   0   7   42
chr4    36259133    36259244    D   0   7   43
chr5    36259333    36259444    E   0   10  47
chr6    25497759    25497870    F   1   11  48
chr7    25497819    25497930    G   1   11  48
chr8    25497869    25497980    H   1   12  49
按相同顺序排列的文件 如果可以安全地假设每个文件中的行的顺序相同,那么您可以使用以下方法非常简洁地完成此工作:

awk '
FILENAME != oname { FN++; oname = FILENAME }
    { p[FNR] = $1; s[FNR] = $2; e[FNR] = $3; n[FNR] = $4; f[FN,FNR] = $5; N = FNR }
END {
    printf("%-8s %-12s %-12s %-4s %-5s %-5s %-5s\n",
           "Part", "Start", "End", "Name", "File1", "File2", "File3");
    for (i = 1; i <= N; i++)
    {
        printf("%-8s %-12d %-12d %-4s %-5d %-5d %-5d\n",
               p[i], s[i], e[i], n[i], f[1,i], f[2,i], f[3,i]);
    }
}' file_1.txt file_2.txt file_3.txt
不同顺序的文件 如果您不能依赖于每个文件中的记录顺序相同,那么您必须更加努力。假设第一个文件中的记录按所需顺序排列,则以下脚本将按顺序打印记录:

awk '
FILENAME != oname { FN++; oname = FILENAME }
    { key = $1 SUBSEP $2 SUBSEP $3 SUBSEP $4
      if (FN == 1)
      {   p[key] = $1; s[key] = $2; e[key] = $3; n[key] = $4; f[FN,key] = $5; k[FNR] = key; N = FNR }
      else
      {   if (key in p)
            f[FN,key] = $5
          else
              printf "Unmatched key (%s) in %s\n", key, FILENAME
      }
    }
END {
    printf("%-8s %-12s %-12s %-4s %-5s %-5s %-5s\n",
           "Part", "Start", "End", "Name", "File1", "File2", "File3")
    for (i = 1; i <= N; i++)
    {
        key = k[i]
        printf("%-8s %-12d %-12d %-4s %-5d %-5d %-5d\n",
               p[key], s[key], e[key], n[key], f[1,key], f[2,key], f[3,key])
    }
}' "$@"
  • 文件_5.txt

    chr8    25497869    25497980    H   1
    chr7    25497819    25497930    G   1
    chr6    25497759    25497870    F   1
    chr5    36259333    36259444    E   0
    chr4    36259133    36259244    D   0
    chr3    128205112   128205223   C   0
    chr2    128205033   128205154   B   0
    chr1    101845021   101845132   A   0
    
    chr2    128205033   128205154   B   7
    chr8    25497869    25497980    H   12
    chr3    128205112   128205223   C   7
    chr1    101845021   101845132   A   6
    chr6    25497759    25497870    F   11
    chr4    36259133    36259244    D   7
    chr7    25497819    25497930    G   11
    chr5    36259333    36259444    E   10
    
    chr5    36259333    36259444    E   47
    chr4    36259133    36259244    D   43
    chr6    25497759    25497870    F   48
    chr8    25497869    25497980    H   49
    chr2    128205033   128205154   B   41
    chr3    128205112   128205223   C   42
    chr7    25497819    25497930    G   48
    chr1    101845021   101845132   A   41
    
  • 文件_6.txt

    chr8    25497869    25497980    H   1
    chr7    25497819    25497930    G   1
    chr6    25497759    25497870    F   1
    chr5    36259333    36259444    E   0
    chr4    36259133    36259244    D   0
    chr3    128205112   128205223   C   0
    chr2    128205033   128205154   B   0
    chr1    101845021   101845132   A   0
    
    chr2    128205033   128205154   B   7
    chr8    25497869    25497980    H   12
    chr3    128205112   128205223   C   7
    chr1    101845021   101845132   A   6
    chr6    25497759    25497870    F   11
    chr4    36259133    36259244    D   7
    chr7    25497819    25497930    G   11
    chr5    36259333    36259444    E   10
    
    chr5    36259333    36259444    E   47
    chr4    36259133    36259244    D   43
    chr6    25497759    25497870    F   48
    chr8    25497869    25497980    H   49
    chr2    128205033   128205154   B   41
    chr3    128205112   128205223   C   42
    chr7    25497819    25497930    G   48
    chr1    101845021   101845132   A   41
    
  • 该脚本将生成以下输出:

    Part     Start        End          Name File1 File2 File3
    chr8     25497869     25497980     H    1     12    49   
    chr7     25497819     25497930     G    1     11    48   
    chr6     25497759     25497870     F    1     11    48   
    chr5     36259333     36259444     E    0     10    47   
    chr4     36259133     36259244     D    0     7     43   
    chr3     128205112    128205223    C    0     7     42   
    chr2     128205033    128205154    B    0     7     41   
    chr1     101845021    101845132    A    0     6     41   
    
    有许多情况下,这些脚本不能完全适应。例如,如果文件的长度不同;如果有重复按键;如果在一个或两个文件中找到密钥,而在其他文件中找不到密钥;如果第五列数据不是数字;如果第二列和第三列不是数字;如果仅列出两个文件,或列出三个以上的文件。“非数字”问题实际上很容易解决;只需使用
    %s
    而不是
    %d
    。但是脚本是脆弱的。它们在所示的生态系统中起作用,但不是很普遍。必要的修复并不是难以置信的困难;但是,它们必须编码,这是一个麻烦

    可能有多于或少于3个文件 扩展上一个脚本以处理任意数量的文件,并输出制表符分隔的数据而不是格式化(可读)的数据并不困难

    awk '
    FILENAME != oname { FN++; file[FN] = oname = FILENAME }
        { key = $1 SUBSEP $2 SUBSEP $3 SUBSEP $4
          if (FN == 1)
          {   p[key] = $1; s[key] = $2; e[key] = $3; n[key] = $4; f[FN,key] = $5; k[FNR] = key; N = FNR }
          else
          {   if (key in p)
                  f[FN,key] = $5
              else
              {
                  printf "Unmatched key (%s) in %s\n", key, FILENAME
                  exit 1
              }
    
          }
        }
    END {
        printf("%s\t%s\t%s\t%s", "Part", "Start", "End", "Name")
        for (i = 1; i <= FN; i++) printf("\t%s", file[i]);
        print ""
        for (i = 1; i <= N; i++)
        {
            key = k[i]
            printf("%s\t%s\t%s\t%s", p[key], s[key], e[key], n[key])
            for (j = 1; j <= FN; j++)
                printf("\t%s", f[j,key])
            print ""
        }
    }' "$@"
    
    按相同顺序排列的文件 如果可以安全地假设每个文件中的行的顺序相同,那么您可以使用以下方法非常简洁地完成此工作:

    awk '
    FILENAME != oname { FN++; oname = FILENAME }
        { p[FNR] = $1; s[FNR] = $2; e[FNR] = $3; n[FNR] = $4; f[FN,FNR] = $5; N = FNR }
    END {
        printf("%-8s %-12s %-12s %-4s %-5s %-5s %-5s\n",
               "Part", "Start", "End", "Name", "File1", "File2", "File3");
        for (i = 1; i <= N; i++)
        {
            printf("%-8s %-12d %-12d %-4s %-5d %-5d %-5d\n",
                   p[i], s[i], e[i], n[i], f[1,i], f[2,i], f[3,i]);
        }
    }' file_1.txt file_2.txt file_3.txt
    
    不同顺序的文件 如果您不能依赖于每个文件中的记录顺序相同,那么您必须更加努力。假设第一个文件中的记录按所需顺序排列,则以下脚本将按顺序打印记录:

    awk '
    FILENAME != oname { FN++; oname = FILENAME }
        { key = $1 SUBSEP $2 SUBSEP $3 SUBSEP $4
          if (FN == 1)
          {   p[key] = $1; s[key] = $2; e[key] = $3; n[key] = $4; f[FN,key] = $5; k[FNR] = key; N = FNR }
          else
          {   if (key in p)
                f[FN,key] = $5
              else
                  printf "Unmatched key (%s) in %s\n", key, FILENAME
          }
        }
    END {
        printf("%-8s %-12s %-12s %-4s %-5s %-5s %-5s\n",
               "Part", "Start", "End", "Name", "File1", "File2", "File3")
        for (i = 1; i <= N; i++)
        {
            key = k[i]
            printf("%-8s %-12d %-12d %-4s %-5d %-5d %-5d\n",
                   p[key], s[key], e[key], n[key], f[1,key], f[2,key], f[3,key])
        }
    }' "$@"
    
  • 文件_5.txt

    chr8    25497869    25497980    H   1
    chr7    25497819    25497930    G   1
    chr6    25497759    25497870    F   1
    chr5    36259333    36259444    E   0
    chr4    36259133    36259244    D   0
    chr3    128205112   128205223   C   0
    chr2    128205033   128205154   B   0
    chr1    101845021   101845132   A   0
    
    chr2    128205033   128205154   B   7
    chr8    25497869    25497980    H   12
    chr3    128205112   128205223   C   7
    chr1    101845021   101845132   A   6
    chr6    25497759    25497870    F   11
    chr4    36259133    36259244    D   7
    chr7    25497819    25497930    G   11
    chr5    36259333    36259444    E   10
    
    chr5    36259333    36259444    E   47
    chr4    36259133    36259244    D   43
    chr6    25497759    25497870    F   48
    chr8    25497869    25497980    H   49
    chr2    128205033   128205154   B   41
    chr3    128205112   128205223   C   42
    chr7    25497819    25497930    G   48
    chr1    101845021   101845132   A   41
    
  • 文件_6.txt

    chr8    25497869    25497980    H   1
    chr7    25497819    25497930    G   1
    chr6    25497759    25497870    F   1
    chr5    36259333    36259444    E   0
    chr4    36259133    36259244    D   0
    chr3    128205112   128205223   C   0
    chr2    128205033   128205154   B   0
    chr1    101845021   101845132   A   0
    
    chr2    128205033   128205154   B   7
    chr8    25497869    25497980    H   12
    chr3    128205112   128205223   C   7
    chr1    101845021   101845132   A   6
    chr6    25497759    25497870    F   11
    chr4    36259133    36259244    D   7
    chr7    25497819    25497930    G   11
    chr5    36259333    36259444    E   10
    
    chr5    36259333    36259444    E   47
    chr4    36259133    36259244    D   43
    chr6    25497759    25497870    F   48
    chr8    25497869    25497980    H   49
    chr2    128205033   128205154   B   41
    chr3    128205112   128205223   C   42
    chr7    25497819    25497930    G   48
    chr1    101845021   101845132   A   41
    
  • 该脚本将生成以下输出:

    Part     Start        End          Name File1 File2 File3
    chr8     25497869     25497980     H    1     12    49   
    chr7     25497819     25497930     G    1     11    48   
    chr6     25497759     25497870     F    1     11    48   
    chr5     36259333     36259444     E    0     10    47   
    chr4     36259133     36259244     D    0     7     43   
    chr3     128205112    128205223    C    0     7     42   
    chr2     128205033    128205154    B    0     7     41   
    chr1     101845021    101845132    A    0     6     41   
    
    有许多情况下,这些脚本不能完全适应。例如,如果文件的长度不同;如果有重复按键;如果在一个或两个文件中找到密钥,而在其他文件中找不到密钥;如果第五列数据不是数字;如果第二列和第三列不是数字;如果仅列出两个文件,或列出三个以上的文件。“非数字”问题实际上很容易解决;只需使用
    %s
    而不是
    %d
    。但是脚本是脆弱的。它们在所示的生态系统中起作用,但不是很普遍。必要的修复并不是难以置信的困难;但是,它们必须编码,这是一个麻烦

    可能有多于或少于3个文件 扩展上一个脚本以处理任意数量的文件,并输出制表符分隔的数据而不是格式化(可读)的数据并不困难

    awk '
    FILENAME != oname { FN++; file[FN] = oname = FILENAME }
        { key = $1 SUBSEP $2 SUBSEP $3 SUBSEP $4
          if (FN == 1)
          {   p[key] = $1; s[key] = $2; e[key] = $3; n[key] = $4; f[FN,key] = $5; k[FNR] = key; N = FNR }
          else
          {   if (key in p)
                  f[FN,key] = $5
              else
              {
                  printf "Unmatched key (%s) in %s\n", key, FILENAME
                  exit 1
              }
    
          }
        }
    END {
        printf("%s\t%s\t%s\t%s", "Part", "Start", "End", "Name")
        for (i = 1; i <= FN; i++) printf("\t%s", file[i]);
        print ""
        for (i = 1; i <= N; i++)
        {
            key = k[i]
            printf("%s\t%s\t%s\t%s", p[key], s[key], e[key], n[key])
            for (j = 1; j <= FN; j++)
                printf("\t%s", f[j,key])
            print ""
        }
    }' "$@"
    

    假设这三个文件都已排序,则可以使用
    join
    命令:

    join -o "1.1,1.2,1.3,1.4,2.5,2.6,1.5" file3 <(join -o "1.1,1.2,1.3,1.4,1.5,2.5" file1 file2)
    

    假设这三个文件都已排序,则可以使用
    join
    命令:

    join -o "1.1,1.2,1.3,1.4,2.5,2.6,1.5" file3 <(join -o "1.1,1.2,1.3,1.4,1.5,2.5" file1 file2)
    

    嗨,约翰,我不知道该怎么办?因为我只想从每个文件中添加第5列作为最终文件中的新列。是的,所有文件都有相同的读取记录。另外,我想给这些列添加标题,因为我知道我的文件需要什么标题。嗨,John,我不知道该怎么做?因为我只想从每个文件中添加第5列作为最终文件中的新列。是的,所有文件都有相同的读取记录。此外,我还想为这些列添加标题,因为我知道我要为我的文件添加什么标题。我可能应该补充一点,我怀疑我忽略了一个简单的解决方案,尽管再次强调,这取决于代码在面对数据文件中的不规则时需要有多大的弹性。嗨,Jon,感谢您的输入,但是,此代码不发送创建制表符分隔的文件输出。如果我有三个以上的文件呢。每次文件的数量都会有所不同。是否有一个统一的awk代码可供使用,而不考虑我拥有的文件数量?因此,将格式更改为在字段之间使用制表符(
    \t
    );也删除字段大小。这种改变很容易。我给出了格式良好的输出。如果你想要标签,那很好,但是它们不能很好地呈现在屏幕上。原则上,在将OFS设置为
    “\t”
    后,可以将
    printf
    调用替换为
    print
    调用。文件数量的变化主要是安排在循环中打印尾随字段的问题,而不是像代码中那样硬编码3。再次,直截了当地处理。但是,由于
    print
    以换行符结束其输出,因此您必须返回到
    printf
    ,我无法循环它。抱歉,我是新手。@RonicK:请参阅我答案底部的“更新”部分。我可能应该补充一点,我怀疑我忽略了一个简单的解决方案,不过,这取决于代码在面对数据文件中的不规则时需要有多大的弹性。嗨,Jon,谢谢你的输入,但是,此代码不发送创建制表符分隔的文件输出。如果我有三个以上的文件呢。每次文件的数量都会有所不同。是否有一个统一的awk代码可供使用,而不考虑我拥有的文件数量?因此,将格式更改为在字段之间使用制表符(
    \t
    );也删除字段大小。这种改变很容易。我给出了格式良好的输出。如果你想要标签,那很好,但是它们不能很好地呈现在屏幕上。原则上,在将OFS设置为
    “\t”
    后,可以将
    printf
    调用替换为
    print
    调用。变数