生信分析的日常,本质上是 “重复劳动的艺术”—— 当你面对 100 个 RNA-seq 样本、500 个 ChIP-seq 峰值文件,或 1000 个基因的功能注释需求时,手动逐个处理不仅耗时(可能花 3 天),更会引入 “复制粘贴错误”(比如第 87 个样本漏改参数)。这时候,混合脚本整合(Shell+Python+R) 就成了破局关键:用 Shell 调度流程、Python 清洗数据、R 做统计可视化,三者各司其职,能把 3 天的工作量压缩到 3 小时,且结果可复现。
本文从生信批量处理的核心痛点出发,拆解三大工具的 “能力边界” 与协作逻辑,通过 3 个递进式实战案例(从单样本流程到批量多组学分析),手把手教你写出 “一次编写、终身复用” 的混合脚本,附带完整代码模板与避坑指南。
一、为什么需要混合脚本?生信批量处理的痛点与解决方案
生信数据的 “批量特性” 体现在三个维度:样本量大(少则几十,多则上千)、文件格式杂(FASTQ、BAM、VCF、CSV 等)、流程步骤多(从质控到差异分析要经过 10 + 步骤)。单一工具根本 hold 不住:
- 只靠 Shell:能批量跑流程,但处理表格数据(如提取表达矩阵的特定基因)时,用 awk 写几十行代码不如 Python 的 pandas 一行解决;
- 只靠 Python:能处理复杂数据,但调用命令行工具(如 fastqc、STAR 比对)时, subprocess 模块远不如 Shell 的管道直观;
- 只靠 R:统计可视化很强,但批量读取上百个文件时,效率远低于 Shell+Python 的组合。
混合脚本的核心逻辑:让每个工具做它最擅长的事 ——
| 工具 | 核心优势 | 生信批量场景举例 |
|---|---|---|
| Shell | 文件操作、命令行调度、流程串联 | 批量下载数据、调用质控工具、建索引 |
| Python | 表格处理、格式转换、复杂逻辑判断 | 批量清洗表达矩阵、提取特定变异位点 |
| R | 统计分析、批量可视化、生信包支持 | 批量做差异分析、画火山图 / 热图 |
举个直观例子:处理 100 个 RNA-seq 样本的 “质控→比对→定量→差异分析” 流程,纯手动需要重复 100 次单样本操作(每次 30 分钟,共 50 小时);用混合脚本只需 1 次配置,自动跑完所有样本(全程约 6 小时,含等待时间),且中间步骤出错能准确定位。
二、单工具批量处理能力拆解:各自的 “独门秘籍”
在学整合前,先掌握每个工具的批量处理核心技巧 —— 这些是混合脚本的 “积木”。
1. Shell:批量文件操作与流程调度的 “总指挥”
Shell(bash 为主)的核心优势是直接调用命令行工具和批量处理文件,尤其适合生信流程中 “重复性命令执行” 环节。
(1)批量处理文件的 3 个核心语法
- 循环遍历:对目录下所有文件执行相同操作(如给 100 个 FASTQ 文件跑 fastqc);
- 管道与重定向:串联多个命令(如从 BAM 文件中提取染色体区域并统计 reads 数);
- 变量与参数传递:用变量存储样本名、路径,避免硬编码(方便修改和复用)。
实战 1:批量对 FASTQ 文件运行 fastqc 质控假设数据目录raw_data/下有 100 个*.fastq.gz文件,需批量生成质控报告:
#!/bin/bash
# 批量fastqc脚本:batch_fastqc.sh
# 定义数据目录和输出目录(用变量方便修改)
DATA_DIR="raw_data"
OUT_DIR="fastqc_reports"
mkdir -p $OUT_DIR # 确保输出目录存在
# 循环遍历所有fastq.gz文件
for fastq in $DATA_DIR/*.fastq.gz; do
# 提取文件名(不含路径和后缀),用于后续命名
sample=$(basename $fastq .fastq.gz)
echo "Processing sample: $sample"
# 运行fastqc,输出到指定目录,加--quiet减少冗余输出
fastqc -o $OUT_DIR -t 4 --quiet $fastq
# 检查命令是否成功执行(生信流程中关键步骤必须加校验)
if [ $? -ne 0 ]; then
echo "Error: fastqc failed for $sample"
exit 1 # 出错时退出脚本,避免继续浪费时间
fi
done
echo "All samples processed. Reports saved to $OUT_DIR"
关键技巧:
- 用
basename提取样本名,避免文件名含路径导致的混乱; - 加
if [ $? -ne 0 ]判断命令执行结果,中途出错立即停止; - 用
-t 4指定线程数,平衡速度与资源占用。
(2)批量调用工具并传递参数
当需要对文件按 “样本对” 处理(如 RNA-seq 的双端数据sample1_R1.fastq.gz和sample1_R2.fastq.gz),可通过正则匹配批量获取成对文件:
实战 2:批量用 STAR 比对双端 FASTQ 文件假设已构建好基因组索引,需比对所有双端数据:
#!/bin/bash
# 批量STAR比对脚本:batch_star_align.sh
INDEX_DIR="genome_index/star" # 基因组索引目录
DATA_DIR="raw_data"
OUT_DIR="aligned_bam"
mkdir -p $OUT_DIR
# 提取所有R1文件,通过正则匹配对应的R2文件
for r1 in $DATA_DIR/*_R1.fastq.gz; do
# 从R1文件名中替换"_R1"为"_R2",得到R2文件
r2=${r1/_R1/_R2}
sample=$(basename $r1 _R1.fastq.gz) # 提取样本名(如sample1)
# 检查R2文件是否存在(避免漏文件导致报错)
if [ ! -f $r2 ]; then
echo "Error: R2 file for $sample not found: $r2"
exit 1
fi
echo "Aligning sample: $sample"
# 运行STAR比对,输出BAM文件
STAR --runMode alignReads \
--genomeDir $INDEX_DIR \
--readFilesIn $r1 $r2 \
--readFilesCommand zcat \ # 处理gz压缩文件
--outFileNamePrefix $OUT_DIR/$sample. \
--outSAMtype BAM SortedByCoordinate \ # 输出排序的BAM
--runThreadN 8 \
--quantMode GeneCounts # 同时输出基因计数矩阵
if [ $? -ne 0 ]; then
echo "Error: STAR failed for $sample"
exit 1
fi
done
echo "All alignments done. BAMs saved to $OUT_DIR"
关键技巧:
- 用
${r1/_R1/_R2}快速匹配双端文件,避免手动写每个样本对; - 加
--readFilesCommand zcat直接处理压缩文件,无需提前解压; - 输出带样本名前缀的 BAM,方便后续批量处理。
2. Python:批量数据清洗与格式转换的 “瑞士军刀”
Python 的优势是处理结构化数据(表格、JSON 等)和复杂逻辑判断,生信中常用于批量清洗测序数据结果(如从 GTF 文件提取基因信息、过滤表达矩阵低丰度基因)。
(1)批量读取文件与表格处理(pandas 核心)
pandas 是 Python 处理表格数据的 “神器”,能批量读取多个 CSV/TSV 文件,合并成大矩阵(如生信中常用的样本 × 基因表达矩阵)。
实战 3:批量合并多个样本的基因计数矩阵STAR 比对后每个样本会生成ReadsPerGene.out.tab(基因计数文件),需合并成一个 “样本 × 基因” 的矩阵:
# 批量合并计数矩阵:merge_counts.py
import os
import pandas as pd
# 输入目录(STAR输出的计数文件)和输出文件
input_dir = "aligned_bam"
output_file = "count_matrix.csv"
# 存储所有样本的计数数据
count_dict = {}
# 遍历目录下所有计数文件
for filename in os.listdir(input_dir):
# 筛选STAR生成的计数文件(文件名格式:sample.ReadsPerGene.out.tab)
if filename.endswith("ReadsPerGene.out.tab"):
# 提取样本名(去掉后缀)
sample = filename.split(".ReadsPerGene.out.tab")[0]
print(f"Processing sample: {sample}")
# 读取计数文件(STAR的计数文件前4行是不同strand,取第2列:unstranded)
# 列名:基因ID、计数(unstranded)、计数(stranded)、计数(reverse stranded)
df = pd.read_csv(
os.path.join(input_dir, filename),
sep="\t",
header=None,
names=["gene_id", f"{sample}_unstranded", f"{sample}_stranded", f"{sample}_reverse"]
)
# 只保留基因ID和unstranded计数(生信常用)
count_dict[sample] = df[["gene_id", f"{sample}_unstranded"]]
# 合并所有样本的计数(按gene_id对齐)
# 从第一个样本开始,逐个与其他样本合并
if count_dict:
merged_df = count_dict[next(iter(count_dict.keys()))] # 取第一个样本的df
for sample, df in count_dict.items():
if sample != next(iter(count_dict.keys())): # 跳过第一个样本
merged_df = merged_df.merge(df, on="gene_id", how="inner") # 内连接,保留所有样本共有的基因
# 保存合并后的矩阵
merged_df.to_csv(output_file, index=False)
print(f"Merged count matrix saved to {output_file} (shape: {merged_df.shape})")
else:
print("No count files found!")
关键技巧:
- 用
os.listdir批量遍历文件,结合endswith筛选目标文件; - 用字典
count_dict暂存每个样本的数据,最后通过merge按基因 ID 合并; - 保留 “内连接”(how="inner"),避免样本间基因 ID 不一致导致的 NA。
(2)批量格式转换与逻辑过滤
生信数据格式多样(GTF、VCF、BED 等),Python 可批量转换为表格并按条件过滤(如从 VCF 中提取特定染色体的高频变异)。
实战 4:批量过滤 VCF 文件中的高频变异假设有 10 个 VCF 文件,需提取染色体 1-5、等位基因频率(AF)>0.5 的变异:
# 批量过滤VCF:filter_vcf.py
import os
import pandas as pd
input_dir = "vcf_files"
output_dir = "filtered_vcf"
os.makedirs(output_dir, exist_ok=True)
# VCF文件的列名(前8列固定,后面是样本列)
vcf_columns = [
"CHROM", "POS", "ID", "REF", "ALT", "QUAL", "FILTER", "INFO"
]
# 遍历所有VCF文件
for filename in os.listdir(input_dir):
if filename.endswith(".vcf"):
sample = filename.split(".vcf")[0]
input_path = os.path.join(input_dir, filename)
output_path = os.path.join(output_dir, f"{sample}_filtered.vcf")
print(f"Processing {filename}...")
# 读取VCF(跳过注释行##,从#CHROM开始)
df = pd.read_csv(
input_path,
sep="\t",
comment="##", # 跳过##开头的元数据
header=0, # #CHROM行为列名
names=vcf_columns # 手动指定列名(避免样本列干扰)
)
# 过滤条件1:染色体为1-5(格式如"chr1"需处理为数字)
df["CHROM_NUM"] = df["CHROM"].str.replace("chr", "").astype(int) # 提取数字
df = df[df["CHROM_NUM"].between(1, 5)]
# 过滤条件2:INFO字段中AF(等位基因频率)>0.5
# INFO格式如"AF=0.6;AC=3;...",提取AF值
df["AF"] = df["INFO"].str.extract(r"AF=(\d+\.\d+)").astype(float)
df = df[df["AF"] > 0.5]
# 保存过滤后的VCF(保留原始格式,去掉中间列)
df = df.drop(columns=["CHROM_NUM", "AF"]) # 移除临时列
df.to_csv(output_path, sep="\t", index=False)
print(f"Filtered {len(df)} variants saved to {output_path}")
关键技巧:
- 用
comment="##"跳过 VCF 的元数据行,只读数据; - 用正则
str.extract从 INFO 字段提取 AF 值,处理非结构化信息; - 中间列(如 CHROM_NUM、AF)用于过滤,最后删除以保留原始格式。
3. R:批量统计分析与可视化的 “绘图大师”
R 在生信中的核心价值是统计建模(如 DESeq2 差异分析)和批量可视化(用 ggplot2 循环画火山图),尤其适合处理 “样本 × 基因” 矩阵后的下游分析。
(1)批量差异分析(DESeq2 实战)
对合并后的计数矩阵,批量做多个处理组 vs 对照组的差异分析:
# 批量差异分析:batch_deseq.R
library(DESeq2)
library(dplyr)
# 输入文件:计数矩阵和样本分组信息(样本名+分组)
count_matrix <- read.csv("count_matrix.csv", row.names = "gene_id") # 行设为基因ID
sample_info <- read.csv("sample_info.csv") # 列:sample_id, group(Control/Treatment1/Treatment2)
# 确保样本名顺序一致(计数矩阵列名 = sample_info$sample_id)
count_matrix <- count_matrix[, sample_info$sample_id]
# 构建DESeq2数据集
dds <- DESeqDataSetFromMatrix(
countData = count_matrix,
colData = sample_info,
design = ~ group # 按group分组
)
# 过滤低表达基因(提高效率)
dds <- dds[rowSums(counts(dds)) > 10, ]
# 标准化与差异分析
dds <- DESeq(dds)
# 定义比较组(多个处理组vs对照组)
comparisons <- list(
c("group", "Treatment1", "Control"),
c("group", "Treatment2", "Control")
)
# 批量提取差异结果并保存
for (comp in comparisons) {
# 提取比较组名称(如Treatment1_vs_Control)
contrast_name <- paste(comp[2], "vs", comp[3], sep="_")
print(paste("Processing comparison:", contrast_name))
# 提取差异结果(log2FC、padj等)
res <- results(dds, contrast = comp) %>%
as.data.frame() %>%
rownames_to_column("gene_id") %>% # 基因ID从行名转为列
arrange(padj) # 按padj排序
# 保存结果
write.csv(res, paste0(contrast_name, "_diff_genes.csv"), row.names = FALSE)
print(paste("Saved", nrow(res), "genes to", paste0(contrast_name, "_diff_genes.csv")))
}
关键技巧:
- 用
list定义多个比较组,循环批量处理; - 差异结果中用
rownames_to_column将基因 ID 转为列,方便后续 Python/Shell 处理; - 提前过滤低表达基因(rowSums>10),减少计算量。
(2)批量可视化(ggplot2 循环绘图)
对每个比较组的差异基因,批量绘制火山图和 Top10 差异基因箱线图:
# 批量可视化:batch_visualization.R
library(ggplot2)
library(dplyr)
# 定义论文级主题(复用前文可视化指南中的函数)
theme_paper <- function() {
theme_bw() +
theme(
plot.title = element_text(hjust = 0.5, size = 12, face = "bold", family = "Arial"),
axis.title = element_text(size = 10, family = "Arial"),
axis.text = element_text(size = 8, family = "Arial"),
legend.text = element_text(size = 8, family = "Arial")
)
}
# 获取所有差异分析结果文件
diff_files <- list.files(pattern = "*_diff_genes.csv")
# 批量画火山图
for (file in diff_files) {
comp_name <- gsub("_diff_genes.csv", "", file) # 提取比较组名称
df <- read.csv(file)
# 分组:显著上调/下调/无差异
df <- df %>%
mutate(
group = case_when(
log2FoldChange > 1 & padj < 0.05 ~ "Up",
log2FoldChange < -1 & padj < 0.05 ~ "Down",
TRUE ~ "NS"
)
)
# 绘制火山图
p <- ggplot(df, aes(x = log2FoldChange, y = -log10(padj), color = group)) +
geom_point(alpha = 0.7) +
geom_vline(xintercept = c(-1, 1), linetype = "dashed", color = "gray50") +
geom_hline(yintercept = -log10(0.05), linetype = "dashed", color = "gray50") +
scale_color_manual(values = c("Up" = "#E74C3C", "Down" = "#3498DB", "NS" = "#95A5A6")) +
labs(title = paste("Volcano Plot:", comp_name), x = "log2(Fold Change)", y = "-log10(FDR)") +
theme_paper()
# 保存图片
ggsave(paste0(comp_name, "_volcano.pdf"), p, width = 8, height = 6, dpi = 300)
print(paste("Saved volcano plot for", comp_name))
}
# 批量画Top10差异基因箱线图(需用到原始计数矩阵)
count_matrix <- read.csv("count_matrix.csv", row.names = "gene_id")
sample_info <- read.csv("sample_info.csv")
for (file in diff_files) {
comp_name <- gsub("_diff_genes.csv", "", file)
df <- read.csv(file)
# 取Top10显著上调基因(按log2FC排序)
top10_genes <- df %>%
filter(group == "Up") %>%
arrange(desc(log2FoldChange)) %>%
slice(1:10) %>%
pull(gene_id)
# 提取这些基因的表达量,并转换为长格式(适合ggplot2)
expr_long <- count_matrix[top10_genes, ] %>%
t() %>% # 转置为样本×基因
as.data.frame() %>%
rownames_to_column("sample_id") %>%
tidyr::pivot_longer(cols = -sample_id, names_to = "gene_id", values_to = "count") %>%
left_join(sample_info, by = "sample_id") # 合并分组信息
# 绘图
p <- ggplot(expr_long, aes(x = group, y = log2(count + 1), fill = group)) +
geom_boxplot(alpha = 0.7) +
geom_jitter(width = 0.2, alpha = 0.5, size = 0.8) +
facet_wrap(~gene_id, ncol = 2) + # 按基因分面
scale_fill_manual(values = c("Control" = "#95A5A6", "Treatment1" = "#E74C3C", "Treatment2" = "#F39C12")) +
labs(title = paste("Top10 Up-regulated Genes:", comp_name), y = "log2(Count + 1)") +
theme_paper() +
theme(legend.position = "none")
ggsave(paste0(comp_name, "_top10_boxplot.pdf"), p, width = 10, height = 12, dpi = 300)
print(paste("Saved boxplot for", comp_name))
}
关键技巧:
- 用
list.files(pattern)批量获取目标文件,避免手动输入; - 用
facet_wrap按基因分面,一次性画多个基因的箱线图; - 计数数据加 1 后取 log2,避免 0 值导致的 - inf。
三、混合脚本整合实战:从单样本到批量多组学的全流程
单一工具的批量处理是 “点”,混合脚本整合是 “线”。下面通过一个完整案例,展示如何用 Shell 串联 Python 和 R 脚本,实现 “RNA-seq 批量分析全流程”。
案例:批量处理 100 个 RNA-seq 样本的完整流程
目标:输入 100 个双端 FASTQ 文件,输出每个比较组的差异基因列表和可视化图表。流程:数据下载→批量质控→比对→计数合并→差异分析→批量可视化工具分工:
- Shell:调度整个流程,调用 fastqc、STAR;
- Python:合并计数矩阵;
- R:差异分析和绘图。
步骤 1:编写总调度 Shell 脚本(串联所有步骤)
总脚本batch_rna_seq_pipeline.sh负责:定义参数→创建目录→按顺序调用各工具脚本→输出日志。
#!/bin/bash
# RNA-seq批量分析总流程:batch_rna_seq_pipeline.sh
# 用法:bash batch_rna_seq_pipeline.sh
# -------------------------- 参数配置(根据实际修改) --------------------------
DATA_DIR="raw_data" # 原始FASTQ文件目录
INDEX_DIR="genome_index/star" # STAR基因组索引
SAMPLE_INFO="sample_info.csv" # 样本分组信息(sample_id, group)
THREADS=8 # 线程数
# ------------------------------------------------------------------------------
# 创建输出目录(按步骤分类,清晰整洁)
mkdir -p fastqc_reports # 质控报告
mkdir -p aligned_bam # 比对后的BAM文件
mkdir -p count_matrix # 计数矩阵
mkdir -p diff_results # 差异分析结果
mkdir -p plots # 可视化图表
mkdir -p logs # 日志文件
# 记录开始时间和日志
START_TIME=$(date +"%Y-%m-%d %H:%M:%S")
echo "Pipeline started at: $START_TIME" > logs/pipeline.log
# 步骤1:批量质控(调用前面写的batch_fastqc.sh)
echo "Step 1/5: Running fastqc..." | tee -a logs/pipeline.log
bash batch_fastqc.sh >> logs/fastqc.log 2>&1 # 日志重定向到文件
if [ $? -ne 0 ]; then
echo "Step 1 failed! Check logs/fastqc.log" | tee -a logs/pipeline.log
exit 1
fi
# 步骤2:批量STAR比对(调用batch_star_align.sh)
echo "Step 2/5: Running STAR alignment..." | tee -a logs/pipeline.log
bash batch_star_align.sh >> logs/star.log 2>&1
if [ $? -ne 0 ]; then
echo "Step 2 failed! Check logs/star.log" | tee -a logs/pipeline.log
exit 1
fi
# 步骤3:Python合并计数矩阵(调用merge_counts.py)
echo "Step 3/5: Merging count matrices..." | tee -a logs/pipeline.log
python3 merge_counts.py >> logs/merge_counts.log 2>&1
if [ $? -ne 0 ]; then
echo "Step 3 failed! Check logs/merge_counts.log" | tee -a logs/pipeline.log
exit 1
fi
# 移动合并后的矩阵到指定目录
mv count_matrix.csv count_matrix/
# 步骤4:R批量差异分析(调用batch_deseq.R)
echo "Step 4/5: Running differential expression..." | tee -a logs/pipeline.log
Rscript batch_deseq.R >> logs/deseq.log 2>&1
if [ $? -ne 0 ]; then
echo "Step 4 failed! Check logs/deseq.log" | tee -a logs/pipeline.log
exit 1
fi
# 移动差异结果到指定目录
mv *diff_genes.csv diff_results/
# 步骤5:R批量可视化(调用batch_visualization.R)
echo "Step 5/5: Generating plots..." | tee -a logs/pipeline.log
Rscript batch_visualization.R >> logs/visualization.log 2>&1
if [ $? -ne 0 ]; then
echo "Step 5 failed! Check logs/visualization.log" | tee -a logs/pipeline.log
exit 1
fi
# 移动图表到指定目录
mv *.pdf plots/
# 记录结束时间
END_TIME=$(date +"%Y-%m-%d %H:%M:%S")
echo "Pipeline finished at: $END_TIME" | tee -a logs/pipeline.log
echo "All results saved to: count_matrix/, diff_results/, plots/"
核心设计:
- 所有参数集中在顶部,方便修改(如换基因组索引只需改
INDEX_DIR); - 每个步骤的日志单独保存(
fastqc.log、star.log),出错时快速定位; - 用
tee -a同时输出到终端和日志文件,实时查看进度; - 步骤间用
if [ $? -ne 0 ]校验,前一步失败则停止,避免无效计算。
步骤 2:工具间数据传递的关键细节
混合脚本的核心是 “数据流转”,三个工具通过文件和参数传递信息:
- Shell→Python:Shell 生成的 BAM 文件(
aligned_bam/sample1.ReadsPerGene.out.tab)作为 Python 的输入; - Python→R:Python 合并的
count_matrix.csv作为 R 差异分析的输入; - R→Shell:R 输出的差异基因 CSV 和 PDF 图表,由 Shell 移动到指定目录。
确保数据一致性的技巧:
- 所有文件路径用绝对路径(如
/home/user/project/raw_data),避免脚本在不同目录运行时出错; - 样本命名保持一致(如
sample1在 FASTQ、BAM、计数矩阵中名称统一); - 关键中间文件(如计数矩阵)加校验(如用 Python 检查行数是否等于基因数)。
步骤 3:运行与调试
- 赋权并运行
chmod +x batch_rna_seq_pipeline.sh batch_fastqc.sh batch_star_align.sh
bash batch_rna_seq_pipeline.sh
- 调试技巧:
- 若某步失败,查看对应日志(如
logs/star.log),搜索 “Error” 定位问题; - 首次运行可先用 1-2 个样本测试(在
raw_data中放少量文件),成功后再扩量; - 用
set -x在脚本开头开启调试模式(会打印每个执行的命令),排查语法错误。
四、效率优化与避坑指南:让批量处理更快、更稳
1. 并行加速:从 “串行等待” 到 “多任务并行”
生信批量处理的瓶颈往往是时间,合理并行能大幅提速:
- Shell 并行:用
xargs -P批量并行处理文件(如同时跑 4 个样本的 fastqc):
# 并行版fastqc(比for循环快4倍)
ls $DATA_DIR/*.fastq.gz | xargs -n 1 -P 4 bash -c '
fastq=$0
sample=$(basename $fastq .fastq.gz)
fastqc -o $OUT_DIR -t 2 --quiet $fastq
'
# -n 1:每次传递1个文件;-P 4:4个进程并行
- Python 并行:用
multiprocessing模块并行处理多个文件:
from multiprocessing import Pool
def process_vcf(filename):
# 单个VCF文件的处理逻辑(同实战4)
...
# 并行处理,4个进程
with Pool(4) as p:
p.map(process_vcf, vcf_files) # vcf_files是所有VCF文件的列表
- R 并行:DESeq2 支持多线程(通过
BiocParallel):
library(BiocParallel)
register(MulticoreParam(workers = 8)) # 8线程
dds <- DESeq(dds, parallel = TRUE)
2. 避坑清单:90% 的人会踩的 5 个坑
-
路径陷阱:脚本中用相对路径,切换工作目录后出错。解:用
SCRIPT_DIR=$(cd $(dirname $0); pwd)获取脚本所在目录,所有路径基于此拼接:SCRIPT_DIR=$(cd $(dirname $0); pwd) # 脚本所在目录 DATA_DIR="$SCRIPT_DIR/raw_data" # 绝对路径 -
文件名含特殊字符:样本名含空格(如
sample 1.fastq)导致循环出错。解:批量重命名文件,用下划线代替空格:for file in *' '*.fastq.gz; do mv "$file" "${file// /_}" # 空格替换为下划线 done -
内存爆炸:Python/R 读取超大矩阵(如 10 万基因 ×1000 样本)时内存不足。解:分块处理(Python 用
pandas.read_csv(chunksize=1000),R 用readr::read_csv_chunked)。 -
工具版本不一致:不同样本用不同版本的 STAR 比对,结果不可比。解:脚本开头记录工具版本,并固定版本(如用 conda 环境):
echo "STAR version: $(STAR --version)" >> logs/versions.log echo "Python version: $(python3 --version)" >> logs/versions.log -
日志丢失:命令报错但没记录日志,无法排查。解:所有命令的输出(stdout 和 stderr)都重定向到日志:
command >> log.txt 2>&1 # 2>&1表示将错误输出合并到标准输出
五、总结:混合脚本的 “道” 与 “术”
生信批量处理的核心不是 “写复杂脚本”,而是用工具链解决实际问题:
- 术:掌握 Shell 循环、Python pandas、R ggplot2 的批量语法;
- 道:理解数据流转逻辑,让每个工具做它最擅长的事。
从今天起,遇到批量任务时,先问自己三个问题:
- 哪些步骤适合用 Shell 调度?(文件操作、命令行工具调用)
- 哪些数据需要 Python 清洗?(表格处理、格式转换)
- 哪些分析适合用 R 完成?(统计建模、可视化)
按这个逻辑搭建的混合脚本,不仅能提升效率,更能让你的分析流程可复现、易维护 —— 这也是生信研究从 “手动操作” 走向 “工程化” 的关键一步。



2493

被折叠的 条评论
为什么被折叠?



