【问题标题】:Fill empty fields - awk填写空白字段 - awk
【发布时间】:2018-07-11 15:27:22
【问题描述】:

我有三个文件,

A.txt
DRR033612   184474
DRR033613   232882
DRR033614   66017
DRR033615   189965
DRR033616   118663
DRR029180   8439

B.txt
DRR033615   1
DRR033616   3

C.txt
DRR033615   5
DRR029180   10
DRR033612   20

我想用下面的 awk 命令总结一下:

cat *.txt | awk 'BEGIN{FS=OFS="\t"}{unique[$1]=(unique[$1] FS $2); next}END{for (i in unique) print i,unique[i]}'

我基本上是根据第一列加入文件。 A.txt 包含所有项目。

不幸的是,该命令没有按我想要的方式工作,即DRR033612 20 行的值20 没有写入正确的字段中。

这是我的输出:

DRR033614       66017
DRR029180       8439    10
DRR033615       189965  1   5
DRR033616       118663  3
DRR033612       184474  20
DRR033613       232882

这是我想要的输出:

DRR033614       66017
DRR029180       8439        10
DRR033615       189965  1   5
DRR033616       118663  3
DRR033612       184474      20
DRR033613       232882

另外,我希望所有空单元格都替换为0

【问题讨论】:

  • 您已经很好地解释了它,但我认为如果您在给定示例输入的情况下包含您想要的输出,它会更有帮助。这会给人们一些明确的东西来测试他们的解决方案。
  • 脚本需要注意文件名何时更改,然后将默认字段添加到该通道中尚未更新的任何唯一元素。
  • 如果B.txtC.txt 中的条目在A.txt 中不存在,您能否扩展您的输出?假设B.txt 包含条目DRR033620 100
  • A.txt 包含所有项目
  • 你应该在你的问题中提到这一点

标签: bash awk multiple-columns


【解决方案1】:

使用 GNU awk 实现真正的多维数组和 ARGIND:

$ cat tst.awk
{ vals[$1][ARGIND] = $2 }
END {
    for (key in vals) {
        printf "%s", key
        for (fileNr=1; fileNr<=ARGIND; fileNr++) {
            printf "\t%d", vals[key][fileNr]
        }
        print ""
    }
}

$ awk -f tst.awk A.txt B.txt C.txt
DRR033614       66017   0       0
DRR029180       8439    0       10
DRR033615       189965  1       5
DRR033616       118663  3       0
DRR033612       184474  0       20
DRR033613       232882  0       0

【讨论】:

    【解决方案2】:

    在辅助函数中使用join

    $ function j() { join -a1 -e0 -o1.1,1.2,"$3"2.2 <(sort $1) <(sort $2); } 
    
    $ j <(j file1 file2) file3 1.3, | column -t
    
    DRR029180  8439    0  10
    DRR033612  184474  0  20
    DRR033613  232882  0  0
    DRR033614  66017   0  0
    DRR033615  189965  1  5
    DRR033616  118663  3  0
    

    这是按键排序的,您可以恢复第一个文件的原始顺序,但在您的预期输出中似乎不是这样。

    【讨论】:

      【解决方案3】:

      我会争取明天有时间写一个适当的解释,但这应该可以解决问题:

      awk 'BEGIN { FS = OFS = "\t" }\
        { if (ARGIND != previousArg) { 
            previousArg = ARGIND;
            for (i in unique) { unique[i] = (unique[i] FS) }} 
          unique[$1]=(unique[$1] $2); next
        }
      END {
        for (i in unique) print i,gensub(/\t\t/, "\t0\t", "g", unique[i])
      }' *.txt
      

      【讨论】:

        【解决方案4】:

        GNU awk 解决方案:

        awk -v OFS='\t' \
        '{ all[FILENAME][$1] = $2 }
         END{
             for (i in all["A.txt"]) {
                 r = i OFS all["A.txt"][i];
                 r = r OFS int(all["B.txt"][i]) OFS int(all["C.txt"][i]);
                 print r
             }
         }' A.txt B.txt C.txt
        

        输出:

        DRR033614   66017   0   0
        DRR029180   8439    0   10
        DRR033615   189965  1   5
        DRR033616   118663  3   0
        DRR033612   184474  0   20
        DRR033613   232882  0   0
        

        【讨论】:

          猜你喜欢
          • 2017-04-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多