Bash批量替换文件名中意外下划线(含awk FILENAME使用疑问)
嘿,我太懂你这种头疼了——10万多个文件名里的下划线乱跑到不该出现的位置,直接搞崩后续处理,试了awk的FILENAME却发现只能读文件名根本没法改,对吧?别慌,给你几个靠谱的批量重命名方案,都是处理这种大数量文件的实用手段:
方法1:用
rename命令(首选,高效处理海量文件) 注意不同系统的rename有两个常见版本,语法不一样,先看你用的是哪一种:
Perl版rename(大部分Linux发行版、macOS用brew安装的都是这个)
看你的示例文件名,意外的下划线都在括号里(比如(PHA_gran_rgn)),而第一个下划线mg.reads.per.gene_是正常分隔符,那咱们可以精准替换括号内的下划线,不碰正常的那个:
rename 's/(\([^)]*)_([^)]*\))/$1-$2/g' *.tsv
简单解释下这个正则逻辑:
(\([^)]*):捕获左括号(到第一个下划线前的所有内容_:定位要替换的“意外下划线”([^)]*\)):捕获下划线后到右括号)的所有内容$1-$2:把两部分捕获内容用连字符-拼接,替换掉原来的下划线g:全局替换,括号里有多个下划线的话一次性全换掉
要是你想替换除第一个下划线之外的所有下划线,可以用这个技巧:先把所有下划线换成连字符,再把第一个连字符换回下划线,完美保留初始分隔符:
rename 's/_/-/g, s/^([^-]*)-/$1_/' *.tsv
C版rename(部分Debian/Ubuntu默认是这个)
这个版本语法更简单,但正则支持有限,适合简单替换场景。比如要把所有下划线换成连字符(如果需要保留第一个,就得结合其他命令,不如用上面的Perl版方便):
rename '_' '-' *.tsv
方法2:Bash循环+sed(全系统兼容,灵活度拉满)
要是你的系统没有Perl版rename,或者需要自定义更复杂的替换逻辑,用bash循环配合sed处理文件名,再用mv重命名就稳了:
for file in *.tsv; do # 生成新文件名:替换括号内的下划线为连字符 new_file=$(echo "$file" | sed 's/\(\([^)]*\)\)_/\1-/g') # 只在文件名变化时执行重命名,避免无意义操作 if [ "$file" != "$new_file" ]; then mv "$file" "$new_file" fi done
这个循环会逐个处理所有.tsv文件,用sed替换目标下划线后再重命名。虽然处理10万文件的速度比Perl版rename慢一点,但胜在任何类Unix系统都能直接用,不用额外安装工具。
关键提醒
- 先测试再批量操作!找几个典型的测试文件,先小范围运行命令,确认替换结果完全符合预期,再对10万文件动手,避免误操作搞砸数据。
- 文件名里有空格、特殊字符也不用担心,上面的命令都用双引号包裹了文件名,能完美兼容。
内容的提问来源于stack exchange,提问作者crazysantaclaus
相关产品推荐
相关产品推荐

