Bash脚本需求:将文件名缩短至指定长度且不截断完整单词
优化Bash脚本:截断文件名时保留完整单词
现有一段Bash脚本用于遍历文件夹,将长度超过指定值n的文件名缩短至n字符,但当前脚本会直接截断单词(比如将sample file name so long wrangling roose turns bridge.txt截断为sample file name so long wrangling ro.txt)。需要优化为:缩短至长度n时,若会截断完整单词,则移除该被截断的单词,使新文件名以最后一个完整单词结尾(期望输出sample file name so long wrangling.txt)。
优化后的脚本
#!/bin/bash export n=120 # 目标文件名长度 find . -type f \ ! -name '.*' \ -regextype egrep \ ! -regex '.*\.[^/.]{'"$n"',}' \ -regex '.*[^/]{'$((n+1))',}' \ -execdir bash -c ' for f in "${@#./}"; do # 分离文件名主体和扩展名 base="${f%.*}" ext="${f#"$base"}" # 计算文件名主体允许的最大长度(总长度n减去扩展名长度) max_base_len=$((n - ${#ext})) # 如果主体长度超过限制,处理单词截断问题 if [ ${#base} -gt "$max_base_len" ]; then # 截取到允许长度内的部分,再找最后一个空格的位置 truncated_part="${base:0:$max_base_len}" # 从末尾向前找最后一个空格,找不到就用原截断位置(无空格的情况) last_space_pos=$(expr index "${truncated_part[::-1]}" ' ') if [ "$last_space_pos" -gt 0 ]; then # 计算正确的截断位置:max_base_len - last_space_pos + 1 final_base="${base:0:$((max_base_len - last_space_pos + 1))}" # 去除末尾可能的空格(确保以非空格结尾) final_base="${final_base%"${final_base##*[![:space:]]}"}" else # 没有空格,直接截断到允许长度 final_base="${base:0:$max_base_len}" fi else final_base="$base" fi # 拼接新文件名并执行重命名 new_name="${final_base}${ext}" # 避免重命名为相同名称(比如处理后长度刚好等于n的情况) if [ "$f" != "$new_name" ]; then mv -- "$f" "$new_name" fi done' bash {} +
关键改动说明
- 分离文件名主体与扩展名:明确拆分
base(文件名不含扩展名)和ext(包含点的扩展名部分),避免处理时混淆。 - 计算允许的主体长度:
max_base_len= 目标总长度n- 扩展名长度,确保整体文件名长度不超过n。 - 处理单词边界:
- 先截取到允许长度的临时片段
truncated_part。 - 反转该片段,找到第一个空格(对应原片段的最后一个空格)的位置。
- 根据空格位置调整截断点,确保保留完整单词。
- 去除末尾可能的空格,保证文件名以非空格字符结尾。
- 先截取到允许长度的临时片段
- 避免无效重命名:增加判断,只有当新文件名与原文件名不同时才执行
mv,避免不必要的操作。
内容的提问来源于stack exchange,提问作者fuzzybabybunny
相关产品推荐
相关产品推荐

