HOWTO · Bash
使用 Bash 删除文件扩展名
在 Bash 中删除文件名的最后一个后缀,使用 basename 移除已知后缀,并用 cut 提取分隔文本中的字段。
本页内容
在 Bash 中,可用参数展开从文件名字符串中删除最后一个后缀:name="${file%.*}"。模式 %.* 会从末尾删除由点号和任意字符组成的最短匹配,因此前面的点号会保留。这只会修改字符串,不会重命名磁盘上的文件。
运行此示例。示例代码块中的可见标签保持英文,以符合代码块原样保留的要求;示例展示了如何删除最后一个后缀。
本节中的代码以及显示的标签或输出仍为英文。
file='annual.report.html'
name="${file%.*}"
printf '%s\n' "$name"
使用 Bash 参数展开删除后缀
如果文件名已经存储在 Bash 变量中,参数展开通常是最简单的选择,不需要外部命令或管道。可以把结果赋给新变量以保留原值;如果之后不再需要原值,也可以直接赋回原变量。展开变量时请加引号,这样空格和通配符仍会作为文件名文本的一部分。
该模式会删除最后一个点号及其后的所有内容。例如,处理 annual.report.html 后得到 annual.report;处理 notes 时,由于没有可匹配的点号,结果仍是 notes。使用此模式时,像 .profile 这样的点开头名称会变成空字符串;如果数据中包含此类文件名,请单独处理。此规则只按文本操作,不判断后缀是否代表有意义的文件类型。
已知后缀时使用 basename
如果确切知道要删除的后缀,可以使用 basename。它的第二个参数是要移除的后缀,并且只有当该后缀与名称末尾匹配时才会删除。例如,basename "$file" .html 会将 annual.report.html 转换为 annual.report。如果名称以 .HTML 或其他后缀结尾,.html 就不匹配,因此会保留。给变量加引号也能保护输入中的空格。
basename 是外部命令,因此对于已经存储在 Bash 变量中的值,它不如参数展开直接。如果已知后缀的匹配行为正合所需,使用它会很方便。两种方式都不会修改磁盘上的文件。
将 cut 用于分隔文本,而非通用文件名后缀
cut 命令用于从按分隔符划分的文本中选取字段。使用 cut -d '.' -f 1 时,每行输入会按点号拆分,并且只保留第一个字段。如果目标规则是“保留第一个点号之前的文本”,它可用于处理文件名列表。但它不能通用地删除文件名的最后一个扩展名:annual.report.html 会变成 annual,.report 和 .html 都会丢失。
对于以换行分隔的列表,可以将文本通过管道传给 cut,例如:printf '%s\n' "$file" | cut -d '.' -f 1。-d 选项用于指定分隔符,-f 1 用于选择第一个字段。只有当输入确实按分隔符组织,且选取该字段符合目的时,才使用 cut。如果要删除最后一个后缀,应优先使用 Bash 参数展开。
处理包含多个点号的文件名并选择合适方法
包含多个点号的文件名能清楚体现这些方法的差异。对于 archive.part.tar.gz,${file%.*} 只会删除 .gz,留下 archive.part.tar;如果 .gz 是已知后缀,basename "$file" .gz 也会得到相同结果;cut -d '.' -f 1 则只保留 archive。删除最后一个后缀时选择参数展开,删除已知后缀时选择 basename,提取分隔文本中的字段时选择 cut。这些示例只转换文件名文本;要重命名文件系统中的条目,需要另行执行重命名操作。