我有一个这样的文本文件:
Fam1000: CMIN|CMIN_9-RA CMIN|ABC_7-RA GCLA|EFX5.1 GCUC|GCUC_7-RA
Fam1001: GCLA|EFX6.1 GCLA|EFX7.1
Fam1002: GCLA|EFX5.1 GCLA|EFX2.1 GCUC|GCUC_8-RA GCUC|GCUC_8-RA
Fam1003: CMIN|CMIN_001265-RA CMIN|CMIN_007282-RA
在这个文件中,每行包含多个值(以空格分隔)。每个值在管道符号前都有一个特定的组标识符(例如 CMIN|CMIN_9-RA 和 CMIN|ABC_7-RA 属于 CMIN 组)。管道后面的字母可以是任意随机字母和数字。
知道文件中组标识符的总数和名称(在本例中我有 3 个:分别是 CMIN、GCLA 和 GCUC)。现在我想将此文件解析为一个文件,该文件显示每行每个组的值数量。最后,我希望得到这样的输出(可以用空格或制表符分隔):
CMIN GCLA GCUC
Fam1000: 2 1 1
Fam1001: 0 2 0
Fam1002: 0 2 2
Fam1003: 2 0 0
我认为我应该首先删除每个值的 | 后面的所有元素,然后计算每行的唯一标识符的数量,但我不知道如何使用 awk 执行此操作。有人可以帮忙吗?
此外,这只是一个简化的例子,实际文件相当大,有几千行和几十个组。
谢谢。
答案1
虽然不是最漂亮的解决方案,但它确实有效。此脚本已在 Linux Ubuntu 上测试过。它可能无法在 Mac 上运行,因为我使用的是gawk
。
您需要将以下代码保存在文件中,例如parsetext.sh
运行此命令以启用执行:
chmod +x parsetext.sh
然后使用你的 inputfile.txt 运行它:
./parsetext.sh inputfile.txt
以下是完成该作业的脚本:
#!/bin/bash
sed -e 's/|[^ ]\+//g; s/://' "$1"|\
gawk '{
for ( i = 2; i <= NF; i++) {
rows[$1][$i]++
keys[$i]++
}
}
END {
n = asorti(keys, tmp)
printf("\t")
for ( i=1; i<= n; i++) { printf("%s\t", tmp[i]) }
printf("\n")
for ( r in rows ) {
printf("%s\t", r)
for (i=1; i<= n; i++) {
value = 0
k = tmp[i]
if (rows[r][k] > 0) value = rows[r][k]
printf("%s\t", value)
}
printf("\n")
}
}'
示例输出:
CMIN GCLA GCUC
Fam1000 2 1 1
Fam1001 0 2 0
Fam1002 0 2 2
Fam1003 2 0 0