Bash脚本中捕获/usr/bin/time执行时间并进行数值比较的问题
解决Bash中捕获/usr/bin/time输出并进行浮点数比较的问题
你遇到的核心问题有两个:一是**/usr/bin/time的格式化输出默认会发送到标准错误(stderr),而Bash的命令替换$()只捕获标准输出(stdout),导致变量exptime无法正确获取时间值;二是/usr/bin/time输出的是浮点数**,没法用Bash的整数运算语法(( ))直接比较。另外脚本被额外调用两次,大概率是因为long-command指向了脚本自身,触发了递归执行。下面分步解决:
1. 正确捕获/usr/bin/time的执行时间
/usr/bin/time(注意区别于Bash内置的time命令)会把-f参数指定的格式输出到stderr,所以需要将stderr重定向到stdout,让命令替换能捕获到结果:
# 方法1:如果不需要保留long-command的输出,直接将其输出丢弃 exptime=$(/usr/bin/time -f '%e' long-command >/dev/null 2>&1) # 方法2:如果需要保留long-command的正常输出,用文件描述符分离两种输出 exec 3>&1 # 先把当前stdout保存到文件描述符3 exptime=$(/usr/bin/time -f '%e' long-command 2>&1 >&3) # 将time的stderr转stdout,long-command的输出仍到原stdout exec 3>&- # 用完关闭文件描述符3
2. 正确进行浮点数比较
Bash的(( ))语法只支持整数运算,而%e输出的是带小数的时间值(比如79.6或80.3),所以需要用bc或awk这类工具处理浮点数比较:
用bc的写法
if echo "$exptime < 80" | bc -l | grep -q 1; then echo "OK" exit 0 elif echo "$exptime > 80" | bc -l | grep -q 1; then echo "NOK" exit 1 else echo "error" exit 2 # 建议给error状态码,方便后续脚本判断 fi
用awk的写法(更简洁)
# 直接通过awk完成判断和输出 awk -v time="$exptime" ' BEGIN { if (time < 80) { print "OK"; exit 0 } else if (time > 80) { print "NOK"; exit 1 } else { print "error"; exit 2 } }' # 或者把判断逻辑整合到脚本的条件分支里 if awk -v t="$exptime" 'BEGIN{exit !(t < 80)}'; then echo "OK" exit 0 elif awk -v t="$exptime" 'BEGIN{exit !(t > 80)}'; then echo "NOK" exit 1 else echo "error" exit 2 fi
3. 解决脚本被额外调用两次的问题
如果你的long-command就是当前脚本(比如写的是./My.sh),会触发递归调用,导致脚本多次执行。解决方法:
- 确认
long-command是你实际要测试的目标命令,而非脚本自身; - 如果确实需要测试脚本自身,添加递归保护逻辑:
# 脚本开头添加递归检测 if [[ -n "$MY_SCRIPT_RUNNING" ]]; then # 这里放脚本的核心业务逻辑,比如模拟耗时操作 sleep $((RANDOM % 100)) exit 0 fi export MY_SCRIPT_RUNNING=1 # 再执行time命令捕获时间 exptime=$(/usr/bin/time -f '%e' "$0" >/dev/null 2>&1)
完整示例脚本
#!/bin/bash # 递归保护(如果要测试脚本自身的话) if [[ -n "$MY_SCRIPT_RUNNING" ]]; then # 模拟核心业务逻辑,比如随机耗时0-99秒 sleep $((RANDOM % 100)) exit 0 fi export MY_SCRIPT_RUNNING=1 # 捕获执行时间 exptime=$(/usr/bin/time -f '%e' "$0" >/dev/null 2>&1) # 浮点数比较并输出结果 if awk -v t="$exptime" 'BEGIN{exit !(t < 80)}'; then echo "OK" exit 0 elif awk -v t="$exptime" 'BEGIN{exit !(t > 80)}'; then echo "NOK" exit 1 else echo "error" exit 2 fi
内容的提问来源于stack exchange,提问作者TimSO
相关产品推荐
相关产品推荐

