【问题标题】:combine files consisting of two columns合并由两列组成的文件
【发布时间】:2015-09-24 20:59:08
【问题描述】:

我有多个如下所示的文件:

文件1:

rsRNA-2312-n    2
rsRNA-6508-n    2
rsRNA-6382-n    10
rsRNA-951-n 0
rsRNA-6330-n    4
rsRNA-6330-n    11
rsRNA-1385-n    3
rsRNA-4945-n    0
rsRNA-946-n 9

文件2:

rsRNA-552-n 2
rsRNA-5301-n    7
rsRNA-6487-n    0
rsRNA-4945-n    7
rsRNA-2445-n    9
rsRNA-6490-n    2

文件3:

rsRNA-4946-n    1
rsRNA-5058-n    0
rsRNA-552-n 0
rsRNA-849-n 2
rsRNA-3302-n    2
rsRNA-4099-n    0
rsRNA-552-n 1

我想合并文件,创建一个输出,该输出在单独的列中包含每个输入文件的值,在 column1 中包含唯一标识符(输入文件中的第 1 列)。如果在特定输入文件中未找到标识符,则此特定输入的此标识符的计数应为 0。

输出类似(不是真实数据):

identifier   file1   file2    file3
rsRNA-552-n 2    4    5
rsRNA-5301-n    7   12    2
rsRNA-6487-n    0    1    5
rsRNA-4945-n    7   12   1
rsRNA-2445-n    9   4    55
rsRNA-6490-n    2  1    0

正在尝试:

paste <(awk '{print $2}' file1 ) <(awk '{print $2}' file2 ) <(awk '{print $2}' file3) <(awk '{print $2}' file4)

并使用 for 循环:

for f in file*; do
base_name=${f%.txt}
id=${base_name#*_}
awk  > "output${id}"
done

【问题讨论】:

  • 但我有 96 个文件:/

标签: perl awk


【解决方案1】:

使用 shell 循环来操作文本总是错误的方法。只需使用 awk,这就是它的设计目的。使用 GNU awk 4.* 处理真正的多维数组和 ARGIND 并排序 in:

$ cat tst.awk
{
    split($1,a,/-/)
    key = a[2]
    key2name[key] = $1
    key2val[key][ARGIND] = $2
}
END {
    printf "identifier"
    for (fileNr=1;fileNr<=ARGIND;fileNr++) {
        printf "%s%s", OFS, ARGV[fileNr]
    }
    print ""

    PROCINFO["sorted_in"] = "@ind_num_asc"
    for (key in key2name) {
        printf "%s", key2name[key]
        for (fileNr=1;fileNr<=ARGIND;fileNr++) {
            printf "%s%s", OFS, (fileNr in key2val[key] ? key2val[key][fileNr] : 0)
        }
        print ""
    }
}

.

$ awk -f tst.awk file1 file2 file3
identifier file1 file2 file3
rsRNA-552-n 0 2 1
rsRNA-849-n 0 0 2
rsRNA-946-n 9 0 0
rsRNA-951-n 0 0 0
rsRNA-1385-n 3 0 0
rsRNA-2312-n 2 0 0
rsRNA-2445-n 0 9 0
rsRNA-3302-n 0 0 2
rsRNA-4099-n 0 0 0
rsRNA-4945-n 0 7 0
rsRNA-4946-n 0 0 1
rsRNA-5058-n 0 0 0
rsRNA-5301-n 0 7 0
rsRNA-6330-n 11 0 0
rsRNA-6382-n 10 0 0
rsRNA-6487-n 0 0 0
rsRNA-6490-n 0 2 0
rsRNA-6508-n 2 0 0

我添加了 key 的轻微额外复杂性作为第一个字段的数字部分,因此在输出结果时可以在该子字段上按数字排序。

【讨论】:

  • 但我有 96 个文件:/
  • @user2300940 你可以使用awk -f tst.awk file* 其中file* 是来自所有96个文件的通用表达式
  • @user2300940 我展示了它被用于 3 个文件 - 是什么让你认为你不能继续列出 96 个文件或 5,000 个文件,如果你愿意的话?
  • 看起来不错,但是,我的输出中只有 2 列。这些文件相互堆叠
  • 我不知道The files are stacked on top of each other 是什么意思。调试步骤 1)您使用的是 GNU awk 4.0 版或更高版本(awk --version 会告诉您)。第 2 步)您的文件中是否有虚假的控制字符,例如在 Windows 上创建的控制字符(cat -v file 将显示它们,dos2unix 或类似的将删除它们)。
【解决方案2】:

另一种解决方案....

awk '
{ d[$1][FILENAME] = $2 }
END{
    line = "identifier";
    for (i=1; i in ARGV; i++) line = line OFS ARGV[i];
    print line
    for(i in d){
        line = i;
        for (j=1; j in ARGV; j++){
            if(ARGV[j] in d[i]) line = line OFS d[i][ARGV[j]]
            else line = line OFS 0
        }
        print line
    }
}' file1 file2 file3

你得到:

标识符 文件 1 文件 2 文件 3 rsRNA-946-n 9 0 0 rsRNA-4945-n 0 7 0 rsRNA-1385-n 3 0 0 rsRNA-2312-n 2 0 0 rsRNA-6382-n 10 0 0 rsRNA-951-n 0 0 0 rsRNA-6490-n 0 2 0 rsRNA-6330-n 11 0 0 rsRNA-5301-n 0 7 0 rsRNA-5058-n 0 0 0 rsRNA-4946-n 0 0 1 rsRNA-2445-n 0 9 0 rsRNA-552-n 0 2 1 rsRNA-6487-n 0 0 0 rsRNA-4099-n 0 0 0 rsRNA-849-n 0 0 2 rsRNA-3302-n 0 0 2 rsRNA-6508-n 2 0 0

【讨论】:

  • awk ' { d[$1][FILENAME] = $2 } END{ line = "identifier"; for (i=1; i in ARGV; i++) line = line OFS ARGV[i];打印行 for(i in d){ line = i; for (j=1; j in ARGV; j++){ if(ARGV[j] in d[i]) line = line OFS d[i][ARGV[j]] else line = line OFS 0 } print line } } ' rsRNA_N1_grep_cut_cutN1_grep_cut_N1_grep2_N1_grep_N1_* > out.csv
  • awk: 源代码行 2 的语法错误上下文是 { >>> d[$1][
  • 该语法错误是因为您使用的不是 GNU awk 4.0 或更高版本。
  • @user2300940 我的 GNU awk 版本是 4.0.1
猜你喜欢
  • 2015-05-29
  • 1970-01-01
  • 2021-03-27
  • 2011-12-07
  • 1970-01-01
  • 2015-08-16
  • 2013-03-28
  • 1970-01-01
相关资源
最近更新 更多