shell脚本执行慢的关键在于定位真实耗时环节:real时间反映墙钟耗时,user体现cpu计算,sys暴露内核开销;结合/usr/bin/time -v分析i/o与内存,用date +%s.%n细粒度计时,辅以bash -x和strace -c/-t精准识别瓶颈。

Shell脚本执行慢,往往不是语法本身的问题,而是隐藏在命令调用和数据流中的性能瓶颈。用 time 测量是第一步,但关键在于读懂输出、定位真实耗时环节。
看懂 time 输出的三类时间
执行 time ./script.sh 后,你会看到三行时间:
- real:从开始到结束的“墙钟时间”,包含等待(如磁盘读、网络响应、sleep)
- user:脚本自身在用户态消耗的 CPU 时间(比如大量字符串处理、循环计算)
- sys:内核为该进程服务所花的时间(如打开文件、分配内存、创建子进程)
若 real 远大于 user + sys,说明脚本大部分时间在等 I/O 或外部资源;若 user 占比高,需检查循环逻辑或重复计算;若 sys 异常高,可能是频繁 fork 子进程(如循环里写 $(date) 或 $(grep ...))。
用外部 time 获取更详细资源信息
Shell 内置的 time 只显示基础时间。要查看内存、上下文切换、页面错误等,得用 GNU 版本:
- 运行
/usr/bin/time -v ./script.sh,会输出完整资源使用报告 - 重点关注:
Major (requiring I/O) page faults(大页错误多 → 磁盘 I/O 重)、Number of times process was swapped out of main memory(换出次数多 → 内存不足)、File system inputs/outputs(I/O 次数高) - 结果可重定向保存:
/usr/bin/time -v ./script.sh 2> profile.log
对关键代码段做细粒度计时
整体 time 只能告诉你“慢”,不能指出“哪一段慢”。推荐在可疑位置插入纳秒级打点:
- 开始前:
start=$(date +%s.%N) - 结束后:
end=$(date +%s.%N); echo "加载配置耗时: $(echo "$end - $start" | bc -l)s" - 避免在循环内反复调用
date,可先缓存起始时间再批量计算 - 配合
bash -x日志(bash -x ./script.sh 2> trace.log),用grep -n "for\|while\|if" trace.log快速定位逻辑块边界
结合 strace 验证系统调用开销
当 time 显示 sys 时间偏高,说明内核工作繁重。用 strace 直接观察发生了什么:
-
strace -c ./script.sh统计各类系统调用次数和耗时,重点关注execve(启动新进程)、openat/read(文件操作)、wait4(等待子进程) - 若
execve出现数百次,基本确认是循环中滥用$(...)或管道导致的子进程爆炸 - 搭配
-T参数(strace -T ./script.sh 2> strace.log)可看到每次系统调用实际耗时,精准定位卡点











