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

为何批量处理图片的bash脚本需两次终止后才会正常执行?

问题原因

核心触发逻辑

你遇到的现象完全是大数量级文件下的shell通配符扩展阻塞导致的,具体运行逻辑如下:

  • 脚本启动后会先执行files=(./pics/all/*.jpg)这一行,shell需要先完成通配符*.jpg的扩展:遍历目录下所有3万+文件,匹配后缀后把所有符合条件的文件路径全量加载到内存生成数组。这个过程在文件数量极大时耗时非常久,且不会有任何输出,所以你会觉得脚本“没有任何反应”,此时脚本还停留在参数扩展阶段,根本没进入循环逻辑。
  • 第一次按下Ctrl + C时,你终止的是正在进行的通配符扩展/数组构建任务,此时shell会输出当前已完成扩展的所有文件名(就是你看到的完整文件数组打印),但数组实际上已经被成功赋值。第二次按下Ctrl + C时,终止的是shell原本要执行的中断退出流程,反而回到了脚本的后续执行逻辑,所以才会进入循环开始处理图片。

优化方案

不要一次性全量加载文件名到数组,改用find逐文件处理,避免启动阻塞和高内存占用,同时优化原有脚本的性能问题:

# 先统计总文件数,速度远快于通配符扩展
total=$(find ./pics/all -maxdepth 1 -type f -name "*.jpg" | wc -l)
i=0
# 逐行读取find的输出处理,不需要预加载所有文件名
find ./pics/all -maxdepth 1 -type f -name "*.jpg" | while read -r file; do
    filename="${file##*/}"
    # 所有变量加双引号,避免文件名带空格/特殊字符时出错
    convert "$file" -sampling-factor 4:2:0 -strip -quality 1 -interlace JPEG -colorspace RGB "./pics/all_resampled/$filename"
    ((i++))
    # 用bash内置整数运算,不要调用bc,减少子进程开销
    progress=$(( i * 100 / total ))
    echo "$i/$total ${progress}% $file RESAMPLED"
done

如果要进一步提升处理速度,可以用并行工具parallel多进程处理,比单循环效率高几倍:

find ./pics/all -maxdepth 1 -type f -name "*.jpg" | parallel -j $(nproc) convert {} -sampling-factor 4:2:0 -strip -quality 1 -interlace JPEG -colorspace RGB ./pics/all_resampled/{/}

-j $(nproc)表示用和CPU核心数相同的并行进程数,可根据实际需求调整。

内容的提问来源于stack exchange,提问作者Sir Rubberduck

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 03:06:04