应使用 /usr/bin/time -v 获取精确的user/system/elapsed时间及内存、i/o等关键指标,避免bash内置time因子shell、重定向、exec终止等导致的计时偏差。

直接用 time 命令,但默认行为容易误判真实耗时——它显示的是 shell 内置版本,不带详细分项,且在管道中失效。
为什么 time 有时不准?
bash 的 time 是个保留字,不是外部命令。它测的是整个 pipeline 的 wall time,但不输出用户态/系统态时间,也不处理子 shell 中的重定向或变量展开延迟。比如:
time { ./myscript.sh > /dev/null; }
这看似“干净”,其实 { } 引起的子 shell 启动开销也被计入,而你真正想测的只是脚本本身。
- 用
\time(反斜杠强制调用外部/usr/bin/time)才能获得User/System/Elapsed三段式结果 - 脚本含
source或exec时,time会终止在第一个 exec 后,测不到后续进程 - 别依赖
$SECONDS在复杂脚本里计时——它受wait、信号中断、子 shell 作用域影响,值可能跳变
/usr/bin/time -v 能看到什么关键指标?
加 -v(verbose)后输出远超基础三时间,对排查性能瓶颈更直接:
-
Major (requiring I/O) page faults:值高说明频繁读磁盘页,脚本可能内存不足或文件读取低效 -
Average total memory use (kbytes):看实际驻留内存,比ps快照更准 -
Percent of CPU this job got:若远低于 100%,说明 I/O 或锁等待拖慢了执行 - 注意
Command being timed:行末是否含空格或引号——有则说明命令解析被 shell 二次处理,计时已污染
精确到毫秒且兼容管道的替代方案
当需要嵌入 pipeline、或要求 sub-second 精度(如压测),time 不够用:
- 用
date +%s.%N手动打点:start=$(date +%s.%N); ./myscript.sh; end=$(date +%s.%N); echo "elapsed: $(echo "$end - $start" | bc -l)"
注意:bc需支持小数,某些 Alpine 镜像要装bc包 - 管道中计时必须用进程替换:
time bash -c './myscript.sh | grep "done"' 2>&1 | grep real
否则time只包住左边命令 - Python 一行流(无依赖):
python3 -c "import time; s=time.time(); exec(open('./myscript.sh').read()); print(f'elapsed: {time.time()-s:.3f}s')"⚠️仅限纯 bash 脚本,含#!/usr/bin/env bash头会报错
真实场景里,最常被忽略的是子 shell 和重定向带来的隐式开销——测一个 curl 请求耗时,如果写成 time curl ... > file,磁盘写入时间全算进去了;而你要的只是网络响应时间。这时候得拆成两步,或者用 strace -T -e trace=connect,sendto,recvfrom 直接盯系统调用。











