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

Bash进度读取循环遇空变量提前终止,无法显示完成提示

问题描述

通过RESTful API读取下载任务的进度状态并打印时遇到以下问题:

  • 下载完成时,状态会从“running”变为“terminated regularly”,且API不再返回progress字段
  • 脚本中$progress变量会因此为空,导致循环行为异常,无法执行“Download finished.”的输出

运行环境:MacOS Ventura 13.4.1、Bash 3.2.57(1),曾尝试用if语句、循环包裹及-z检查$progress,均未解决问题。期望实现正常显示进度,并在下载完成后给出完成提示。

原脚本:

while true; do
    status=$(curl -s -u admin:admin -H "Accept:application/json" -X GET \
    -i http://1.2.3.4/sessionInformation/1/status | grep "Status" | sed 's/    "Status"://g' | sed 's/"//g')

        while [[ $status != "terminated regularly"  ]]; do
            progress=$(curl -s -u admin:admin -H "Accept:application/json" -X GET \
            -i http://1.2.3.4/sessionInformation/1/status | grep "Progress" | sed 's/["Progress":"      %]//g')
            echo -ne "Download ${progress} % finished.\r"
        done
        echo "Download finished."
    break
done

set -x输出片段:

+ progress=99
+ echo -ne 'Download 99 % finished.\r'
+ [[ running, != \t\e\r\m\i\n\a\t\e\d\ \r\e\g\u\l\a\r\l\y ]]
++ curl -s -u admin:admin -H Accept:application/json -X GET -i http://1.2.3.4/sessionInformation/1/status
++ grep Progress
++ sed 's/["Progress":"      %]//g'
+ progress=
问题分析
  1. 状态提取错误:原脚本通过grep+sed提取状态时,未处理JSON字段后的逗号,导致$status值为running,(而非预期的running),使得[[ $status != "terminated regularly" ]]永远为真,内层循环无法退出
  2. 未实时更新状态:内层循环中未重新获取最新状态,即使API返回terminated regularly,脚本也无法感知
  3. 重复API请求:每次循环分别调用两次curl,既低效又可能触发API限流
  4. 空进度未处理:当progress字段不存在时,直接输出空值,导致显示异常
解决方案

推荐使用jq工具解析JSON(比grep+sed更可靠,MacOS可通过brew install jq安装),同时优化循环逻辑,确保实时更新状态、减少API请求,并处理空进度的情况:

修正后的脚本:

#!/bin/bash
# 配置参数
USER="admin"
PASS="admin"
API_URL="http://1.2.3.4/sessionInformation/1/status"
# 每次请求间隔(避免频繁调用API)
DELAY=1

while true; do
    # 单次请求获取完整JSON响应
    response=$(curl -s -u "${USER}:${PASS}" -H "Accept:application/json" "${API_URL}")
    
    # 用jq提取状态(-r返回原始字符串,不含引号)
    status=$(echo "$response" | jq -r '.Status')
    # 提取进度,若字段不存在则返回空
    progress=$(echo "$response" | jq -r '.Progress // empty')

    # 判断是否下载完成
    if [[ "$status" == "terminated regularly" ]]; then
        # 清理当前行的进度输出,打印完成提示
        echo -ne "\rDownload finished.                     \n"
        break
    fi

    # 根据进度是否存在,输出对应提示
    if [[ -n "$progress" ]]; then
        echo -ne "\rDownload ${progress} % finished."
    else
        echo -ne "\rDownload in progress, waiting for status update..."
    fi

    # 延迟后再进行下一次查询
    sleep "$DELAY"
done

无jq兼容方案

若无法安装jq,可改用grep+sed解析JSON(需注意JSON格式的一致性):

#!/bin/bash
USER="admin"
PASS="admin"
API_URL="http://1.2.3.4/sessionInformation/1/status"
DELAY=1

while true; do
    response=$(curl -s -u "${USER}:${PASS}" -H "Accept:application/json" "${API_URL}")
    
    # 提取状态,去除引号和末尾逗号
    status=$(echo "$response" | grep -o '"Status":"[^"]*"' | sed 's/"Status":"//;s/"//')
    # 提取进度,仅保留数字
    progress=$(echo "$response" | grep -o '"Progress":[0-9]*' | sed 's/"Progress"://')

    if [[ "$status" == "terminated regularly" ]]; then
        echo -ne "\rDownload finished.                     \n"
        break
    fi

    if [[ -n "$progress" ]]; then
        echo -ne "\rDownload ${progress} % finished."
    else
        echo -ne "\rDownload in progress, waiting for status update..."
    fi

    sleep "$DELAY"
done

关键改进点

  • 单次curl请求获取完整响应,减少API调用次数
  • 实时更新状态,确保能及时感知下载完成
  • 处理空进度的边界情况,避免显示异常
  • 添加延迟,避免频繁请求给API服务器造成压力

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 20:42:13