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
相关产品推荐
相关产品推荐

