我有几十千兆字节(基因组数据)的文件,我需要在其中找到子字符串的出现次数。虽然我在这里看到的答案使用grep -o
然后wc -l
,这似乎是一种黑客方式,可能不适用于我需要处理的非常大的文件。
grep -o
/wc -l
方法对于大文件是否具有良好的扩展性?如果没有,我还能怎么做呢?
例如
aaataaaagtcgaaaaagtccatgcatatgatacttttttttttttttttt
111
222
333
444
555
666
必须返回 6 次出现才能aaa
。(除了可能还有1000万行。
在字符串中找到 6 个重叠的子字符串aaa
line="aaataaaagtcgaaaaagtccatgcatatgatacttttttttttttttttt"
你不想看到字符串,你想计算它们。 当你尝试时
# wrong
grep -o -F "aaa" <<< "${line}" | wc -l
您缺少重叠的字符串。
使用子字符串aaa
您在aaaaaaa
中有 5 次命中,那么如何处理${line}
?
入手
grep -Eo "a{3,}" <<< "${line}"
结果
aaa
aaaa
aaaaa
我们有很多点击吗? 1 代表aaa
,2 代表aaaa
,3 代表aaaaa
。 将字符总数与行数进行比较 (wc
):
match lines chars add_to_total
aaa 1 4 1
aaaa 1 5 2
aaaaa 1 6 3
对于每一行,从该行的字符总数中减去 3。
当结果有 3 行和 15 个字符时,计算
15 characters - (3 lines * 3 characters) = 15 - 9 = 6
在代码中:
read -r lines chars < <(grep -Eo "a{3,}" <<< "${line}" | wc -lc)
echo "Substring count: $((chars - (3 * lines)))"
或对于文件
read -r lines chars < <(grep -Eo "a{3,}" "${file}" | wc -lc)
echo "Substring count: $((chars - (3 * lines)))"
aaa
"简单",那么其他搜索字符串呢?
我认为您必须寻找子字符串并考虑一个适用于该子字符串的公式。abcdefghi
不会有重叠的字符串,但abcdabc
可能。
与abcdabc
的潜在匹配项是
abcdabc
abcdabcdabc
abcdabcdabcdabc
使用测试线
line="abcdabcdabcdabc something else abcdabcdabcdabc no match here abcdabc and abcdabcdabc"
你需要"abc(dabc)+"
并拥有
match lines chars add_to_total
abcdabcdabcdabc 1 16 3
abcdabcdabcdabc 1 16 3
abcdabc 1 8 1
abcdabcdabc 1 12 2
对于每一行,从字符总数中减去 4,然后将答案除以 4。或者(characters/4) - nr_line
.当结果有 4 行和 52 个字符时,计算
(52 characters / fixed 4) / 4 lines = 13 - 4 = 9
在代码中:
read -r lines chars < <(grep -Eo "abc(dabc)+" <<< "${line}" | wc -lc)
echo "Substring count: $(( chars / 4 - lines))"
当您有一个大文件时,您可能希望先拆分它。
我想有两种方法(两种方法都报告了 2 条测试行的29/6
):
-
使用求和方法:
# WHINY_USERS=1 is a shell param for mawk-1 to pre-sort array ${input……} | WHINY_USERS=1 {m,g}awk ' BEGIN { 1 FS = "[^a]+(aa?[^a]+)*" 1 OFS = "|" 1 PROCINFO["sorted_in"] = "@ind_str_asc" } { 2 _ = "" 2 OFS = "|" 2 gsub("^[|]*|[|]*$",_, $!(NF=NF)) 2 split(_,__) split($-_,___,"[|]+") 12 for (_ in ___) { 12 __[___[_]]++ } 2 _____=____=_<_ 2 OFS = "t" 2 print " -- line # "(NR) 7 for (_ in __) { 7 print sprintf(" %20s",_), __[_], ______=__[_] * (length(_)-2), "| "(____+=__[_]), _____+=______ } print "" }'
|
-- line # 1
aaa 3 3 | 3 3
aaaa 2 4 | 5 7
aaaaa 3 9 | 8 16
aaaaaaaaaaaaaaa 1 13 | 9 29
-- line # 2
aaa 1 1 | 1 1
aaaa 1 2 | 2 3
aaaaa 1 3 | 3 6
打印出该子字符串的所有副本:
{m,g}awk' { 2 printf("%s%.*s",____=$(_=_<_),_, NF=NF) 9 do { _+=gsub(__,_____) } while(index($+__,__)) 2 if(_) { 2 ____=substr(____,-_<_,_) 2 gsub(".", (":")__, ____) 2 print "}-[(# " (_) ")]--;fb" substr(____, 2) } else { print "" } }' FS='[^a]+(aa?[^a]+)*' OFS='|' __='aaa' _____='aa'
|
aaagtcgaaaaagtccatgcaaataaaagtcgaaaaagtccatgcatatgatactttttttttt
tttttttaaagtcgaaaaagaaaaaaaaaaaaaaatataaaatccatgc}-[(# 29)]--;
aaa:aaa:aaa:aaa:aaa:aaa:aaa:aaa:aaa:aaa:aaa:aaa:aaa:aaa:aaa:aaa:
aaa:aaa:aaa:aaa:aaa:aaa:aaa:aaa:aaa:aaa:aaa:aaa:aaa
aaataaaagtcgaaaaagtccatgcatatgatacttttttttttttttttt}-[(# 6)]--;
aaa:aaa:aaa:aaa:aaa:aaa