如何使用Bash命令提取包含多行数据的聚类?
问题:提取包含多行数据的Cluster聚类
我需要用Bash命令从文本文件中提取聚类,每个聚类以>Cluster开头的行作为分界,只保留包含多行数据的聚类。
输入文件示例:
>Cluster 199 0 2599aa, >CAD5117741.1... * >Cluster 200 0 2579aa, >CAD5112262.1... * >Cluster 201 0 2578aa, >CAD5116287.1... * >Cluster 202 0 2578aa, >CAD5122864.1... * 1 1867aa, >CAD5122865.1... at 100.00% 2 2369aa, >CAD5122866.1... at 100.00% >Cluster 203 0 2573aa, >CAD5110750.1... * >Cluster 204 0 2571aa, >CAD5116249.1... * >Cluster 205 0 2558aa, >CAD5122682.1... * >Cluster 206 0 2553aa, >CAD5126525.1... * >Cluster 207 0 2551aa, >CAD5115834.1... *
期望输出:
只保留包含多行数据的Cluster 202:
>Cluster 202 0 2578aa, >CAD5122864.1... * 1 1867aa, >CAD5122865.1... at 100.00% 2 2369aa, >CAD5122866.1... at 100.00%
尝试的错误命令:
我用了下面的awk命令,但输出不完整:
awk '/^>Cluster/ {cluster=$0; count=0; next} {count++} count > 1 {print cluster; print} count == 0 {print cluster}'
错误输出:
>Cluster 202 2 2369aa, >CAD5122866.1... at 100.00%
解决方案
你需要先缓存当前聚类的所有行,等到遇到下一个聚类开头或者文件结束时,再判断当前聚类的行数是否大于1,若是则输出整个聚类。这里提供两种高效的awk实现方式:
方法一:缓存聚类内容,批量输出
/^>Cluster/ { if (lines > 1) { print buffer } buffer = $0 "\n" lines = 0 next } { buffer = buffer $0 "\n" lines++ } END { if (lines > 1) { print buffer } }
逻辑说明:
- 每遇到新的
>Cluster行,先检查上一个聚类的行数是否大于1,若是则输出缓存的内容 - 重置缓存和行数计数器,把当前聚类开头行存入缓存
- 非聚类开头的行,追加到缓存中并增加行数计数
- 文件结束时,检查最后一个聚类是否符合条件并输出
方法二:逐行判断,实时输出(适合大文件)
如果处理的是超大文件,不想占用过多内存,可以用下面的方式,只记录聚类状态:
/^>Cluster/ { if (in_cluster && count > 1) { print cluster_head print cluster_body } cluster_head = $0 cluster_body = "" count = 0 in_cluster = 1 next } in_cluster { cluster_body = cluster_body $0 "\n" count++ } END { if (in_cluster && count > 1) { print cluster_head print cluster_body } }
测试结果
用上述任意一个命令处理输入文件,都会得到你期望的完整输出。
内容的提问来源于stack exchange,提问作者Rohan Nath
相关产品推荐
相关产品推荐

