批量重命名文件:按下划线分割文件名并保留首尾字段的实现咨询
没问题,我来帮你搞定这个重命名需求,顺便带你吃透awk处理这类场景的思路~
先分析你之前的 rename 问题
你用的 rename 's/^([^_]*).*([^_]*[.]txt)/$1_$2/' *.txt 其实在Perl版rename(比如Debian/Ubuntu默认的rename)下是能工作的,但如果你的系统是util-linux版rename(比如CentOS),它不支持Perl正则,只认简单字符串替换,所以会失效。不过既然你想学习awk,咱们就重点用awk来实现。
用awk实现的完整方案
核心思路就是你想的:按下划线分割文件名,提取首尾字段,再拼接成新文件名。我把完整的命令和逻辑拆解给你:
find . -type f -name "*.txt" | awk '{ # 保存原始文件路径 old_path = $0 # 提取纯文件名(去掉前面的路径,比如把 ./sub/a_b_c.txt 变成 a_b_c.txt) fname = old_path sub(/.*\//, "", fname) # 去掉 .txt 后缀,得到文件名主体(a_b_c) base_name = fname sub(/\.txt$/, "", base_name) # 按下划线分割主体成数组,n是数组长度 n = split(base_name, parts, "_") # 生成新文件名:首字段 + 下划线 + 尾字段 + .txt new_fname = parts[1] "_" parts[n] ".txt" # 避免重命名相同的文件(比如a_b.txt不需要改) if (fname != new_fname) { # 生成新的文件路径(和原文件同目录) new_path = old_path sub(fname, new_fname, new_path) # 输出mv命令,加-v可以看到重命名过程 printf "mv -v \"%s\" \"%s\"\n", old_path, new_path } }' | sh
关键awk知识点拆解
split()函数:split(base_name, parts, "_")会把base_name按下划线分割,存入parts数组,返回值是数组元素个数。awk数组下标从1开始,所以parts[1]是第一个字段,parts[n]是最后一个字段。sub()函数:用来替换字符串,比如sub(/.*\//, "", fname)是把文件名中从开头到最后一个/的内容清空,只留下纯文件名;sub(/\.txt$/, "", base_name)是去掉末尾的.txt后缀。- 字符串拼接:awk里不需要特殊符号,直接把字符串连写就能拼接,比如
parts[1] "_" parts[n] ".txt"自动拼成新的文件名。
测试和安全提示
- 先去掉末尾的
| sh,执行前面的命令,看看输出的mv命令是不是你想要的,确认无误后再加上| sh执行实际重命名。 - 如果只处理当前目录的文件,也可以简化成:
ls *.txt | awk '{ old = $0 base = $0 sub(/\.txt$/, "", base) n = split(base, parts, "_") new = parts[1] "_" parts[n] ".txt" if (old != new) printf "mv -v \"%s\" \"%s\"\n", old, new }' | sh
这样就能完美得到你想要的结果:a_b.txt、a_c.txt、a_e.txt、a_i.txt啦~
内容的提问来源于stack exchange,提问作者DaniCee
相关产品推荐
相关产品推荐

