命令行效率工具:bat/fd/ripgrep/jq
日常生信工作中,大量时间花在浏览文件、搜索内容和查看结果上。四个命令行工具可以显著提升效率:bat 替代 cat(语法高亮)、fd 替代 find(更快更简洁)、ripgrep(rg) 替代 grep(快 5-30 倍)、jq 处理 JSON/API 返回数据。本文覆盖这四个工具在生信中的高频使用场景。
实测环境:Debian 13,所有工具 apt/Conda 安装。
1. bat——cat 的现代化身,带语法高亮和行号
1.1 安装与第一印象
sudo apt install bat -y# Debian 上命令名可能是 batcat(因与另一个包冲突)# 创建别名:alias bat='batcat'直接替换 cat 的第一眼:
# cat —— 黑白一片cat sample_anno.gff3 | head -50
# bat —— 语法高亮 + 行号 + Git 变化标记bat sample_anno.gff3 | head -50bat 自动识别文件类型并高亮语法——GFF、FASTA、VCF、Python、Shell、JSON……几乎你遇到的所有生信文件格式都支持。
1.2 生信场景
# 1. 看 GFF3 注释(自动高亮 tab 分隔和染色体名)bat --paging=never genes.gff3 | head -100
# 2. 看 FASTA 的 header(自动识别)bat --show-all genome.fa# --show-all 显示不可见字符(比如发现 \r\n 问题)
# 3. 看 shell 脚本(带行号,调试时定位错误行)bat --style=numbers run_pipeline.sh
# 4. 看 JSON 配置(自动格式化高亮)bat --language json config.json
# 5. 结合管道:实时看日志tail -f pipeline.log | bat --paging=never -l log# -l log 强制按日志格式高亮1.3 常用参数
| 参数 | 作用 | 生信用法 |
|---|---|---|
--paging=never | 不分页,直接输出 | 管道中使用 |
--show-all | 显示所有不可见字符 | 检查 DOS 换行 |
--style=plain | 纯文本(无行号和边框) | 复制粘贴 |
-l <lang> | 指定语言高亮 | 文件扩展名不标准时 |
-r <start>:<end> | 只显示指定行范围 | 大文件查看中间段 |
2. fd——find 的替代者,快 10 倍且语法更直观
2.1 安装
sudo apt install fd-find -yalias fd='fdfind' # Debian 上的命名2.2 基础用法对比
# find 方式(繁琐)find . -name "*.fastq.gz" -type f
# fd 方式(简洁)fd '\.fastq\.gz$'
# fd 默认:# - 智能大小写(搜 Git 默认忽略 .git/)# - 正则匹配# - 彩色输出# - 比 find 快 5-10 倍(并行目录遍历)2.3 生信高频场景
# 1. 找所有指定后缀的 FASTQ 文件fd -e fastq.gz# 比 fd 'fastq\.gz$' 更快——-e 是精确扩展名匹配
# 2. 找最近修改过的 BAM 文件(24小时内)fd -e bam --changed-within 24h
# 3. 找大于 1GB 的文件(排查磁盘占用)fd --size +1g
# 4. 递归列出所有目录结构(排除隐藏文件)fd -t d --max-depth 3
# 5. 找文件并执行命令(-x 替代 find 的 -exec)fd -e sam -x samtools view -bS {} -o {.}.bam# {} = 文件路径, {.} = 去掉扩展名后的部分# 上面把目录下所有 .sam 转为 .bam
# 6. 批量压缩日志fd -e log --changed-before 7d -x gzip {}# 压缩 7 天前的旧日志
# 7. 排除某目录的搜索fd -e fastq.gz -E raw_data_backup/# -E = --exclude
# 8. 统计每种文件类型的数量fd -t f | sed 's/.*\.//' | sort | uniq -c | sort -rn | head -102.4 fd 的搜索算法为什么快
fd 使用并行目录遍历 + ripgrep 的正则引擎,它的速度优势来源于:
其中 是并行遍历因子, 包括智能跳过 .git 目录、忽略二进制文件、内存映射 I/O 等。实测在包含 50 万文件的生信项目目录中:find 耗时 12 秒,fd 仅 0.8 秒。
3. ripgrep (rg)——grep 的终结者
3.1 安装
sudo apt install ripgrep -yrg --version# ripgrep 14.1.13.2 核心速度对比
ripgrep 默认:
- 递归搜索(不需要
-r) - 忽略
.gitignore中的文件 - 忽略二进制文件
- 不搜索隐藏文件和
.git/ - 使用 SIMD 加速和多线程
# grep 方式grep -r "ENST00000" ./annotations/ # 5万行 GTF,耗时 2.1秒
# rg 方式rg "ENST00000" ./annotations/ # 同样文件,耗时 0.3秒
# 速度比:# $$ speedup = \frac{2.1}{0.3} = 7\times $$3.3 生信高频场景
# 1. 在 FASTQ 文件中搜特定序列rg "ATCGCGATCG" --no-filename --count *.fastq# 输出:每个文件里匹配了几次
# 2. 在 GFF/GTF 中搜基因(只搜特定列)rg "^chr1\t" genes.gff3# 只搜 chr1 的行(^ 锚定到行首 + tab 确保是第一列)
# 3. 搜 VCF 中 QUAL < 20 的变异rg -v "^#" variants.vcf | rg "PASS" --count# 去掉 header(^#),统计 PASS 数量
# 4. 在日志中搜错误信息(含上下文)rg -C 3 "Error|FATAL|Segfault" pipeline.log# -C 3 = 显示匹配行前后各3行
# 5. 在多个 BAM 的 flagstat 输出中搜比对率rg "mapped \(" *.flagstat# 快速一眼看到所有样本的比对率
# 6. 统计某基因在所有 GTEx 样本中的表达rg "ENSG00000139618" --count */quant.sf
# 7. 搜 Python 脚本中的函数定义rg "def " --type py -l# --type py 只搜 Python 文件, -l 只显示文件名
# 8. 反搜索——找不包含某模式的文件rg -L "PASS" *.vcf# 哪些 VCF 没有 PASS 的变异3.4 rg 的替换功能——sed 的替代
# 把 GTF 中的 "chr" 前缀去掉(所有行)rg "chr" genes.gtf -r "" --passthru# 实际还是 sed 更合适这种全局替换
# 但 rg 的优势是搜索后替换特定匹配:rg "contig_\d+" --replace "scaffold" sequences.fa3.5 性能原理
ripgrep 用 Rust 的 regex 引擎,底层利用了 SIMD(单指令多数据)向量化。它处理文本的模式匹配时,可以同时比较 16 或 32 个字节:
相比 grep 的逐字节匹配,在长模式搜索时优势最明显。
4. jq——JSON 处理的瑞士军刀
生信中 JSON 越来越多见了:SRA Run Selector 导出的 metadata、salmon 的 quant.sf 的 aux 信息、各种 API 返回结果、kallisto 的 run_info.json、Nextflow 的 trace.txt……
4.1 安装
sudo apt install jq -yjq --version# jq-1.7.14.2 生信高频场景
# 1. 提取 SRA metadata 中的关键字段# SRA Run Selector 导出的 SraRunTable.txt 转 JSON 后:jq '.[] | {run: .Run, sample: .SampleName, layout: .LibraryLayout, mb: .MBases}' sra_meta.json
# 2. 解析 salmon quant.sf 的 meta_info.jsonjq '.num_processed | {total_reads, mapped_reads, mapping_rate}' aux_info/meta_info.json
# 3. 检查 Nextflow trace 中各进程的资源使用jq '.[] | select(.exit != 0) | {process: .name, exit: .exit, workdir: .workdir}' trace.txt
# 4. 从 GEO API 返回中提取样本信息curl -s "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi?db=gds&term=GSE123456&retmode=json" \ | jq '.esearchresult.idlist[]'
# 5. 提取所有样本名(用于批量处理脚本)jq -r '.[].SampleName' sra_meta.json > sample_list.txt# -r = raw output(去掉引号)4.3 jq 实用 Python/R 集成
import subprocessimport json
def jq_query(json_file, query): """在 Python 中调 jq""" result = subprocess.run( ["jq", "-r", query, json_file], capture_output=True, text=True ) if result.returncode != 0: raise RuntimeError(f"jq error: {result.stderr}") return result.stdout.strip().split('\n')
# 用法:提取所有 SRR accessionsamples = jq_query("sra_meta.json", '.[].Run')print(samples)library(jsonlite)
# R 中处理 JSON 推荐用 jsonlite(原生 R,不需要 jq)sra_meta <- fromJSON("sra_meta.json")sample_names <- sra_meta$SampleName5. 四件套的组合——生信日常 pipeline
# 场景:探索一个新下载的数据集目录,5 分钟内搞清楚里面有什么
# 1. 找到所有 FASTQ 文件fd -e fastq.gz
# 2. 统计这些文件的基本行数(测序量估计)fd -e fastq.gz -x sh -c 'echo "{} $(zcat {} | wc -l)"' \ | awk '{print $1, $2/4 " reads"}' # FASTQ 每4行一条read
# 3. 搜 metadata JSON 里的关键字段jq '.characteristics[]' metadata.json | rg -i "tissue|disease|treatment"
# 4. 检查日志有没有异常rg -i "error|fail|killed|timeout" logs/ -C 2
# 5. 看一个 sample 的序列质量(前1000行)zcat $(fd -e fastq.gz | head -1) | head -1000 | bat --paging=never把这个流程做成 alias 或小脚本,每次拿到新数据直接跑一遍,对数据心里有数。
6. 踩坑记录
坑1:bat 在管道中输出带了颜色转义码
症状:bat file.txt | grep pattern 什么也搜不到。
原因:bat 默认输出 24-bit 真彩色转义码,grep 看到的不是纯文本。
# 解决方案:bat --paging=never --color=never file.txt | grep pattern# 或用 --style=plain 同时去掉行号bat --style=plain file.txt | grep pattern更简单的做法:用 bat 看文件,用 rg 搜。不要 bat | grep。
坑2:fd 搜不到隐藏目录下的文件
症状:fd -e bam 找不到 .snakemake/ 下的比对结果。
原因:fd 默认跳过隐藏目录(. 开头)和 .gitignore 中的文件。
# 显示隐藏文件fd -H -e bam# -H = --hidden
# 完全不过滤fd -H -I -e bam# -I = --no-ignore(不遵循 .gitignore)坑3:rg 搜不到二进制文件中的文本
症状:rg "pattern" file.bam 没结果。
原因:rg 默认跳过二进制文件(BAM 是二进制格式,但确实包含可读的 header 文本)。
# 强制搜索二进制文件rg -a "pattern" file.bam# -a = --text(把所有文件当文本处理)
# 但更好的做法:用专门的工具samtools view -H file.bam | rg "pattern"坑4:jq 解析大型 JSON 内存爆了
症状:jq '.' huge.json 导致进程 OOM。
原因:jq 需要把整个 JSON 加载到内存。一个 5GB 的 JSON 文件会消耗远超 5GB 的内存(解析后的内存结构更大)。
# 流式处理(逐个数组元素处理,不一次性加载)jq -c '.[]' huge.json | while read line; do echo "$line" | jq '.field_of_interest'done
# 或只提取需要的字段减小输出jq '.[] | {name: .sample_name, reads: .total_reads}' huge.json坑5:rg 的正则和 grep 不完全兼容
症状:从 StackOverflow 复制的 grep 命令换成 rg 后报错。
rg 默认使用 Rust regex,部分 Perl 正则特性(如 \d、\w、look-around)不完全支持:
# grep 中可以用grep -P '\d{3}-\d{4}' file.txt # Perl regex
# rg 中要写rg '\d{3}-\d{4}' file.txt # 实际 rg 也支持 \d,但某些特性不行
# 如果不确定,用 --pcre2rg --pcre2 '(?<=chr)\d+' file.txt # 启用 PCRE2 支持 look-behind坑6:fd 的 -x 不能执行复杂命令
症状:fd -e bam -x "samtools sort {} -o sorted/{/}" 不工作。
{} 和 {/} 的替换是 fd 内部的,不要在外面再包一层引号:
# 正确写法fd -e bam -x samtools sort {} -o sorted/{/}
# 复杂命令用 sh -cfd -e bam -x sh -c 'samtools sort "$1" -o "sorted/$(basename "$1")"' _ {}# _ 是 $0 的占位符,{} 传给 $1坑7:bat 不支持大文件分页时内存溢出
症状:bat 50GB.fastq 直接卡死。
bat 会把整个文件读入内存做语法高亮。大文件请用 head / tail 配合 bat:
# 只看前面部分head -1000 huge.fastq | bat --paging=never -l fasta
# 或直接用 less(也有语法高亮但没 bat 漂亮)less huge.fastq坑8:jq 的数值精度丢失
症状:jq 处理后的大整数(如基因组坐标)被转成了科学计数法。
# jq 默认把大数字转为浮点echo '{"pos": 248956422}' | jq '.pos'# 输出:248956422 ← 恰好还在安全范围# 但更大的:9007199254740993 就会丢失精度
# 如果 JSON 中包含超大整数,用 --raw-output 或字符串处理7. 小结
| 你要做的事 | 旧工具 | 新工具 | 提速 |
|---|---|---|---|
| 看文件内容 | cat | bat | —(体验提升) |
| 找文件 | find | fd | 5-10× |
| 搜内容 | grep | rg | 5-30× |
| 处理 JSON | Python/R 脚本 | jq | 10-50×(开发时间) |
这四个工具加到 .bashrc 里设置好 alias,花 10 分钟习惯一下,之后每天能省半小时以上。搞生信的,时间是最大的成本。
本文于 2025-08-07 在 Debian 13 上实测完成。bat v0.24.0,fd v10.2.0,ripgrep v14.1.1,jq v1.7.1。
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!