我有一个名为Type1.txt的文件,如下所示:
$ cat Type1.txt
ID.580.G3C0
TTTTTTTTTTT
ID.580.G3C8
ATTATATC-AAA
ID.580.GXC16
ATTATTTC-ACG-TTTTTCCTA
ID.694.G9C3
ATTATATC-ACG-AAATCCTA
ID.694.G9C3
etc...
我想编写一个bash脚本来计算每个ID的实例,并将其导出到另一个提供摘要的文件中,如下所示:
ID.580 = 3
ID.694 = 1
etc...
到目前为止,脚本很乱并且无法使用。
对于上述内容,我有以下内容:
#!/bin/bash
for Count in `grep -c "ID.580" Type1.txt; do
echo $Count=ID.580
done > Result.txt #Allows to count only for that single ID.
我有超过一千个ID.XXX,使得此代码无法使用,因为为每次搜索添加单独的ID.XXX是不合理的。感谢您的帮助!
答案 0 :(得分:0)
grep '^ID.[0-9][0-9][0-9]' input_file | cut -c1-6 | sort | uniq -c
作品?
答案 1 :(得分:0)
根据您的特定语料库和分组策略,获得所需结果的方法不止一种。这里有两个替代解决方案,一个在awk中,另一个在Ruby中。
一种方法是使用GNU awk执行以下步骤:
例如:
$ awk '/^ID/ {split($0, a, "."); print a[1] "." a[2]}' /tmp/foo |
sort | uniq --count | awk '{print $2 " = " $1}'
ID.580 = 3
ID.694 = 2
使用您在问题中提供的语料库,我的系统平均需要8毫秒。当然,更大的语料库需要更长的时间,但除非你有一个非常庞大的数据集,否则对于大多数用途来说这应该足够快。
Ruby提供了我认为更优雅的解决方案,但实际上速度较慢。这里的想法是将ID的相关部分存储为哈希键,并在每次遇到给定ID时递增计数器。例如,考虑这个Ruby单行:
$ ruby -ne 'BEGIN { id = Hash.new(0) }
id[$&] += 1 if /\AID\.\d+/
END { id.each_pair do |k,v| puts "#{k} = #{v}" end }' /tmp/foo
ID.580 = 3
ID.694 = 2
此解决方案需要大约45毫秒来处理相同的语料库,因此我不建议仅仅为了转换输出而在awk管道上。这样做的主要优点是你有一个实际的数据结构(例如Hash object),你可以在一个功能更全面的程序中操作。
答案 2 :(得分:0)
下面的代码使用标准的UNIX实用程序,并不假设ID的第二部分正好是3个字符,但是会找到ID.1.123123123
和ID.1234.123123
并正确地只取第一个点 - 划界的部分。因为它是
grep '^ID\.[0-9]' Type1.txt | cut -d . -f 1-2 | sort \
| uniq -c | awk '{ print $2" = "$1 }'
grep
仅过滤以ID.
开头,后跟1位数字(至少)的行cut
使用.
作为字段分隔符,仅输出字段1和2,从而删除
包括第二个.
在内的所有内容。sort
对uniq的行进行排序uniq
打印前缀为count awk
部分会反转这些字段,并使用=
分隔打印它们。如果ID的第一部分也可以包含字母,请将正则表达式的结尾更改为[0-9]
到[0-9A-Z]
。例如
管道输出
ID.580 = 3
ID.694 = 2
由于Python在生物学家中很受欢迎,你可能想要磨练你的python技能:
from collections import Counter
counter = Counter()
with open('Type1.txt') as f:
for line in f:
if line.startswith('ID.'):
top_id = '.'.join(line.split('.', 2)[:2])
counter[top_id] += 1
for top_id, count in sorted(counter.items()):
print("%s = %d" % (top_id, count))
结果完全相同。
答案 3 :(得分:0)
这是awk one liner:
$ awk -F. '$1=="ID"{a[$2,$3]++}END{for (i in a) {split(i,ind,SUBSEP); r[ind[1]]++}for (i in r) print "ID."i" = "r[i]}' file
ID.694 = 1
ID.580 = 3
这是一个纯粹的bash解决方案:
#!/bin/bash
while IFS=. read -r pre id code rest
do
[[ $pre == ID ]] || continue
[[ ${a[$id]} =~ \."$code"\. ]] || {
a[$id]="${a[$id]}.$code."
((count[$id]++));
}
done < file
for i in "${!count[@]}"
do
echo "ID.$i = ${count[$i]}"
done
$ ./script.sh
ID.580 = 3
ID.694 = 1
答案 4 :(得分:-1)
awk也可能有用......
awk '/ID.580/{x++}END{print x}' test.txt
你可以把它放在for循环中
for i in ID.580 ID.694
do
awk '/'$i'/{x++}END{print x}' test.txt
done