<p>最推荐用${file##*.}提取扩展名,如report.tar.gz→gz;无点则为空,.gitignore→gitignore;健壮写法需先判断[[ $file == . ]];配套取主名用${file%.*};避免用basename+sed等外部命令。</p>

在 Linux Shell 中提取文件的扩展名,最常用、最可靠的方式是使用参数扩展(Parameter Expansion),无需调用外部命令如 basename 或 sed,既高效又便携。
用 ${file##*.} 提取最后一个点后的部分
这是最推荐的方法,适用于绝大多数情况:
-
${file##*.}表示“从左边删除最长匹配*.的部分”,即保留最后一个点之后的内容 - 例如:file="report.tar.gz" →
${file##*.}结果为gz - 注意:如果文件名不含点(如
README),结果为空字符串;如果以点开头(如.gitignore),结果为gitignore(因为##*.会匹配空字符串前的点)
更健壮的写法:先判断是否含点再提取
避免误把无扩展名或隐藏文件当扩展名处理:
Linux 性能分析与调优专家,覆盖 CPU、内存、磁盘 I/O、网络、内核参数、编译优化、容器/K8s。适用场景:系统卡顿/高负载、内存不足/OOM/Swap 高、CPU 异常/iowait 高。
[[ $file == *.* ]] && echo "${file##*.}" || echo ""- 或者封装成函数:
ext() { [[ $1 == *.* ]] && echo "${1##*.}"; }
然后用ext "data.csv"得到csv
提取不带扩展名的主文件名(常配套使用)
用 ${file%.*} 去掉最后一个点及之后内容:
-
${file%.*}→ 删除最短匹配.*后缀,如 file="photo.jpeg" →photo - 组合使用:
name=${file%.*}; ext=${file##*.} - 注意:
${file%%.*}(两个 %)会删掉第一个点起全部内容,一般不用
慎用外部命令:basename + sed 不必要且易出错
虽然有人用 basename "$file" | sed 's/.*\.//',但存在明显问题:
- 无法正确处理
archive.tar.gz(可能错误输出tar.gz或空) - 依赖外部命令,性能低,且在最小化系统中可能不可用
- 对含换行或空格的文件名需额外转义,复杂度高

















