Shell脚本如何兼容下划线/连字符 移除文件名末尾日期后缀
可行实现方案
你当前用的${FILE_NM%_*}是bash原生的后缀截断参数扩展,默认只能匹配固定字符,要同时支持下划线、连字符两种分隔符,根据你的场景(后缀为分隔符+8位日期+2位字母),有以下几个可直接落地的方案:
方案1:Bash正则匹配(推荐,无外部依赖、准确率最高)
不需要调用任何外部命令,通过bash内置的正则匹配能力精准识别后缀规则,哪怕文件名主体里同时混用下划线和连字符也不会误截断:
# 注意变量名和你实际存储的变量保持一致,示例里用小写file_nm if [[ $file_nm =~ ^(.*)[_-][0-9]{8}[a-zA-Z]{2}$ ]]; then file_prefix=${BASH_REMATCH[1]} fi
匹配逻辑:
- 捕获分隔符(下划线
_/连字符-二选一)之前的所有内容作为前缀 - 严格校验分隔符后是8位数字+2位字母的日期后缀,不会误切主体里的分隔符
- 对你给出的两个示例,输出结果完全符合预期:
- 下划线格式
File_name_something_somthing_20220215ab处理后得到File_name_something_somthing - 连字符格式
File-name-something-somthing-20220215cd处理后得到File-name-something-somthing
- 下划线格式
方案2:extglob扩展通配符截断(写法最简洁)
如果你的使用场景能确定:要移除的后缀一定是最后一个下划线/连字符开始到末尾的所有内容,不需要严格校验日期格式,可以开启bash的扩展通配符功能,用和你之前写法接近的参数扩展实现:
# 开启扩展通配符,只需要执行一次,当前shell环境全局生效 shopt -s extglob # 匹配末尾的下划线或连字符+后续所有内容,直接截断 file_prefix=${file_nm%@(_|-)*}
注意:这个方案会截断最后一个下划线/连字符后的所有内容,如果文件名主体本身末尾带有分隔符加非日期的内容,会出现误截断。
方案3:分支判断兼容老shell
如果需要兼容不支持[[ ]]正则、不支持extglob的极简shell环境(比如dash),可以通过分支判断分别处理两种分隔符场景:
case $file_nm in *_[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][a-z][a-z]) file_prefix=${file_nm%_*} ;; *-[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][a-z][a-z]) file_prefix=${file_nm%-*} ;; esac
注意事项
- 注意变量名大小写一致性,你之前代码里写的全大写
FILE_NM和你描述里存储文件名的小写file_nm如果不统一,会导致变量读取失败。 - 不建议优先用
sed/awk等外部命令处理,内置参数扩展/正则的性能更高,也不会遇到特殊字符转义问题。
内容的提问来源于stack exchange,提问作者Another Mailbox
相关产品推荐
相关产品推荐

