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

批量重命名文件:按下划线分割文件名并保留首尾字段的实现咨询

没问题,我来帮你搞定这个重命名需求,顺便带你吃透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知识点拆解

  1. split()函数:split(base_name, parts, "_") 会把base_name按下划线分割,存入parts数组,返回值是数组元素个数。awk数组下标从1开始,所以parts[1]是第一个字段,parts[n]是最后一个字段。
  2. sub()函数:用来替换字符串,比如sub(/.*\//, "", fname)是把文件名中从开头到最后一个/的内容清空,只留下纯文件名;sub(/\.txt$/, "", base_name)是去掉末尾的.txt后缀。
  3. 字符串拼接:awk里不需要特殊符号,直接把字符串连写就能拼接,比如parts[1] "_" parts[n] ".txt"自动拼成新的文件名。

测试和安全提示

  1. 先去掉末尾的| sh,执行前面的命令,看看输出的mv命令是不是你想要的,确认无误后再加上| sh执行实际重命名。
  2. 如果只处理当前目录的文件,也可以简化成:
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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 08:27:53