You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Bash中如何结合常量与正则批量匹配替换文件名?

问题描述

现有一批测序数据文件,原文件名格式如下:

S2EC1_DKDL220005480-2a-AK13554-7UDI265_HHJ2MCCX2_L8_1.fq.gz
S2EC1_DKDL220005480-2a-AK13554-7UDI265_HHJ2MCCX2_L8_2.fq.gz
S2EC2_DKDL220005480-2a-5UDI249-7UDI265_HHJ2MCCX2_L8_1.fq.gz
S2EC2_DKDL220005480-2a-5UDI249-7UDI265_HHJ2MCCX2_L8_2.fq.gz
S2EC11_DKDL220005480-2a-5UDI251-5UDI1063_HHJ2MCCX2_L8_1.fq.gz
S2EC11_DKDL220005480-2a-5UDI251-5UDI1063_HHJ2MCCX2_L8_2.fq.gz

需要重命名为:

S2EC1_R1.fastq.gz
S2EC1_R2.fastq.gz
S2EC2_R1.fastq.gz
S2EC2_R2.fastq.gz
S2EC11_R1.fastq.gz
S2EC11_R2.fastq.gz

已知文件名包含固定片段DKDL220005480-2a-和_HHJ2MCCX2_L8,两者之间为可变内容。

已尝试分步执行Bash命令处理:

for x in *; do mv $x ${x/DKDL220005480-2a-/}; done
for x in *; do mv $x ${x/_HHJ2MCCX2_L8_/_R}; done

得到中间文件名:

S2EC1_AK13554-7UDI265_R1.fq.gz
S2EC1_AK13554-7UDI265_R2.fq.gz
S2EC2_5UDI249-7UDI265_R1.fq.gz
S2EC2_5UDI249-7UDI265_R2.fq.gz
S2EC11_5UDI251-5UDI1063_R1.fq.gz
S2EC11_5UDI251-5UDI1063_R2.fq.gz

但执行以下命令移除中间可变部分时出错:

for x in *; do mv $x ${x/_(.+)_/}; done

错误信息:

mv: 'S2EC1_AK13554-7UDI265_R1.fq.gz' and 'S2EC1_AK13554-7UDI265_R1.fq.gz' are the same file
mv: 'S2EC1_AK13554-7UDI265_R2.fq.gz' and 'S2EC1_AK13554-7UDI265_R2.fq.gz' are the same file
mv: 'S2EC2_5UDI249-7UDI265_R1.fq.gz' and 'S2EC2_5UDI249-7UDI265_R1.fq.gz' are the same file
mv: 'S2EC2_5UDI249-7UDI265_R2.fq.gz' and 'S2EC2_5UDI249-7UDI265_R2.fq.gz' are the same file
mv: 'S2EC11_5UDI251-5UDI1063_R1.fq.gz' and 'S2EC11_5UDI251-5UDI1063_R1.fq.gz' are the same file
mv: 'S2EC11_5UDI251-5UDI1063_R2.fq.gz' and 'S2EC11_5UDI251-5UDI1063_R2.fq.gz' are the same file
错误原因

Bash的参数扩展${parameter/pattern/string}使用的是通配符(glob)匹配,而非正则表达式语法。你写的_(.+)_会被当作字面字符串匹配,而文件名中不存在该字符串,因此替换操作未执行,导致mv命令的源文件和目标文件完全相同,触发错误。

解决方案

方案一:修正中间文件的重命名命令

针对当前的中间文件名,用Bash通配符匹配替换中间可变部分:

for x in *.fq.gz; do
    # 替换第一个_到第二个_之间的所有内容为单个_
    temp=${x/_*_/_}
    # 将.fq.gz后缀替换为.fastq.gz
    new_name=${temp/.fq.gz/.fastq.gz}
    mv "$x" "$new_name"
done

解释:

  • _*_是通配符模式,匹配第一个_开始到下一个_结束的所有内容(即中间的可变部分),替换为单个_后得到S2EC1_R1.fq.gz格式。
  • 最后替换后缀,得到目标文件名。

方案二:一步到位直接处理原文件

无需分步操作,直接从原文件名提取前缀和读段编号生成目标文件名,效率更高:

for file in *.fq.gz; do
    # 提取前缀(第一个_DKDL220005480-2a-之前的部分)
    prefix=${file%%_DKDL220005480-2a-*}
    # 提取读段编号(最后一个_之后的数字部分)
    read_num=${file##*_}
    read_num=${read_num%.fq.gz}
    # 拼接目标文件名并执行重命名
    mv "$file" "${prefix}_R${read_num}.fastq.gz"
done

解释:

  • ${file%%_DKDL220005480-2a-*}:从文件名末尾向前删除最长匹配的_DKDL220005480-2a-*,得到前缀如S2EC1。
  • ${file##*_}:从文件名开头向后删除最长匹配的*_,得到1.fq.gz或2.fq.gz,再通过${read_num%.fq.gz}去掉后缀得到数字1或2。
  • 最终拼接出目标文件名${prefix}_R${read_num}.fastq.gz。

内容的提问来源于stack exchange,提问作者Andreanna

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 07:15:50