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

Bash中无额外依赖动态确定任务时长以实现进度条的方案求助

Bash中无额外依赖动态确定任务时长以实现进度条的方案求助

嘿,我完全懂你的痛点——不想硬编码等待时间,也没法用pv,还要在纯Bash里给jar打包任务整个靠谱的进度反馈对吧?你的思路方向是对的,但用pgrep容易误匹配同名进程,咱们可以优化一下,精准追踪你启动的那个jar进程,同时做动态的进度反馈,下面给你两个可行的方案:


方案一:基于进程存活时间的动态进度条(无需提前知道总工作量)

这个方案适合没法提前统计任务总量的情况,核心是捕获jar进程的PID,精准追踪它的运行状态,同时用动态循环的进度条给视觉反馈:

第一步:修改主脚本,传递jar进程的PID

把你原来的主脚本里的打包逻辑改成这样,用$!获取后台运行的jar进程的PID,然后传给load3.sh:

if [ "$selected_choice" == "Go Back" ]
then 
  gsettings set org.gnome.desktop.peripherals.keyboard repeat false && echo -en "\e" # 回到主菜单的转义序列
else 
  cd && cd "$search_dir" 
  # 启动jar打包任务并记录它的PID
  jar cf "$file" "$fileclass" &
  JAR_PID=$!
  # 将PID传给进度条脚本
  bash ~/Bash_Files/Bash_Animations/load3.sh "$JAR_PID"
fi

第二步:改造load3.sh,实现动态进度显示

修改后的load3.sh会接收PID,实时追踪进程状态,同时显示已运行时长和动态进度条:

#!/bin/bash

# 接收传入的目标进程PID
TARGET_PID=$1
if [ -z "$TARGET_PID" ]; then
  echo "错误:需要传入目标进程的PID"
  exit 1
fi

progressBarWidth=20
# 记录任务启动时间
start_time=$(date +%s)

# 检查进程是否存活的辅助函数
is_running() {
  kill -0 "$TARGET_PID" 2>/dev/null
}

# 动态进度显示函数
show_progress() {
  while is_running; do
    # 计算已运行时长
    elapsed=$(( $(date +%s) - start_time ))
    # 生成循环填充的进度条(因为不知道总时长,用循环视觉反馈)
    filled=$(( elapsed % progressBarWidth ))
    empty=$(( progressBarWidth - filled ))
    bar="["$(printf "%${filled}s" | tr ' ' '#')$(printf "%${empty}s" | tr ' ' '.')"]"
    # 用\r刷新当前行,实现动态效果
    echo -ne "\r任务已运行 ${elapsed}s ${bar}"
    sleep 0.5
  done
  # 任务结束后清理行,显示完成信息
  echo -ne "\r任务完成!总耗时 $(( $(date +%s) - start_time ))s            \n"
}

# 启动进度显示
show_progress

# 可选:绑定SIGINFO信号(类BSD系统按Ctrl+T,Linux需手动触发),收到时打印当前耗时
trap 'echo -e "\n当前已运行 $(( $(date +%s) - start_time ))s"' SIGINFO

方案二:基于实际工作量的精准百分比进度条(如果能统计总文件数)

如果你的$fileclass是目录或者文件集合,可以先统计要打包的文件总数,再结合jar的详细输出来计算真实的进度百分比,这个方案更精准:

第一步:修改主脚本,统计总文件数并传递

if [ "$selected_choice" == "Go Back" ]
then 
  gsettings set org.gnome.desktop.peripherals.keyboard repeat false && echo -en "\e" # 回到主菜单的转义序列
else 
  cd && cd "$search_dir" 
  # 统计要打包的文件总数(仅统计普通文件)
  total_files=$(find "$fileclass" -type f | wc -l)
  # 启动带详细输出的jar打包,把输出重定向到临时文件
  jar cfv "$file" "$fileclass" > /tmp/jar_output.log 2>&1 &
  JAR_PID=$!
  # 把PID和总文件数传给进度条脚本
  bash ~/Bash_Files/Bash_Animations/load3.sh "$JAR_PID" "$total_files"
fi

第二步:改造load3.sh,解析输出计算进度

#!/bin/bash

TARGET_PID=$1
TOTAL_FILES=$2
# 检查参数是否齐全
if [ -z "$TARGET_PID" ] || [ -z "$TOTAL_FILES" ]; then
  echo "错误:需要传入目标进程PID和总文件数"
  exit 1
fi

progressBarWidth=20
start_time=$(date +%s)

is_running() {
  kill -0 "$TARGET_PID" 2>/dev/null
}

show_progress() {
  while is_running; do
    # 统计已处理的文件数(jar -v会输出每个打包的文件,行数就是已处理数)
    processed=$(wc -l < /tmp/jar_output.log)
    # 计算完成百分比(避免除以0的情况)
    if [ "$TOTAL_FILES" -gt 0 ]; then
      percent=$(( processed * 100 / TOTAL_FILES ))
      # 确保百分比不超过100
      [ "$percent" -gt 100 ] && percent=100
    else
      percent=0
    fi
    # 计算进度条填充长度
    filled=$(( percent * progressBarWidth / 100 ))
    empty=$(( progressBarWidth - filled ))
    bar="["$(printf "%${filled}s" | tr ' ' '#')$(printf "%${empty}s" | tr ' ' '.')"]"
    elapsed=$(( $(date +%s) - start_time ))
    # 刷新进度条
    echo -ne "\r已完成 ${percent}% ${bar} 已运行 ${elapsed}s"
    sleep 0.5
  done
  # 清理临时日志文件
  rm /tmp/jar_output.log
  # 显示最终完成信息
  echo -ne "\r任务完成!总耗时 $(( $(date +%s) - start_time ))s            \n"
}

show_progress

# 可选:绑定SIGINFO信号,收到时打印当前进度
trap 'processed=$(wc -l < /tmp/jar_output.log); percent=$(( processed * 100 / TOTAL_FILES )); echo -e "\n当前已完成 ${percent}%,已运行 $(( $(date +%s) - start_time ))s"' SIGINFO

小提示

  • 关于SIGINFO:在macOS/BSD系统里,按Ctrl+T会给进程发送SIGINFO信号,触发我们绑定的提示;Linux默认没有这个信号的快捷键,你可以用kill -SIGINFO <load3.sh的PID>来手动触发。
  • 两个方案都不需要额外安装任何工具,纯Bash实现,完全符合你的需求。

备注:内容来源于stack exchange,提问作者Abbatrombone

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.17 09:43:15