linux-在Bash中显示长时间运行的应用程序的进度

我有一些涉及嵌入式系统更新的程序,它们需要按顺序运行,并且需要向单独的系统报告进度.

这些阶段是:

>验证图像;
>将映像文件解压缩为活动磁盘上的文件;和
>将映像安装到备用磁盘.

之后,计算机将重新启动,备用磁盘将变为活动磁盘.

目前,我们报告的初始值为0%,验证结束时为5%,拆包结束时为45%,安装结束时为90%.重新启动后,当新映像开始运行时,将报告100%标记.

现在,尽管我对这种方法感到非常满意,但客户端希望看到更细粒度的更新状态报告.我们已经毫不含糊地让他们知道,此类报告大部分都是人为的,但他们认为有必要让客户满意.

因此,我正在寻找一种方法,可以根据粗糙的时间来报告进度,同时仍然要执行长时间运行的任务并完成工作.

我们知道,从开始到重新启动,整个安装过程大约需要两分钟,而在每个阶段花费的时间将按照给定的百分比分配.

解决方法:

在bash中执行此操作的一种方法是运行一个单独的过程来执行进度报告,并为其提供足够的信息以成功报告.这将涉及:

>起始百分比;
>期末百分比;
>要添加到每个周期的百分比的增量;和
>循环时间.

前两个很明显,它们提供了报告结果的上下限.

另外两个允许您提供报告比率.例如,每秒增加6%将使用这些值(增量= 6,周期= 1),并且每秒将增加6%.

对于较慢的步骤,例如每秒提供0.25%,您可以提供(增量= 1,周期= 4),每四秒钟将添加1%.您实际上并没有报告亚秒级的进度,只是随着时间的推移会平均得出该进度.

那么,这是怎么做的呢?首先,让我们提供一个简单的功能来报告进度.在您的情况下,应将其替换为用于与您提到的“独立系统”进行通信的任何内容.以下代码显示了如何执行此操作:

#!/usr/bin/env bash

doProgress() {
    # Simply echo progress using whatever was passed. Date is included
    # for debugging purposes.

    echo "$(date +%H:%M:%S): $1%"
}

解决方案的“实质”是backgroundReporter()函数,该函数将根据前面提到的四个参数调用doProgress():

backgroundReporter() {
    # Get the four parameters.

    currVal=$1 ; maxVal=$2 ; deltaVal=$3 ; timeGap=$4

    # If signalled to stop, output maximum percentage then exit.
    # Note no output if you've already reached the maximum.

    trap "[[ \${maxVal} -ne \${lastVal} ]] && doProg \${maxVal} ; exit" HUP

    # Infinite loop until signalled.

    while : ; do
        # Wait for the duration, save current percentage, and
        # calculate new percntage (capped at maximum).

        sleep ${timeGap}
        lastVal=${currVal}
        (( currVal = (currVal + deltaVal > maxVal) ? maxVal : currVal + deltaVal ))

        # Log only if it's changed.

        [[ ${currVal} -ne ${lastVal} ]] && doProg ${currVal}
    done
}

唯一棘手的是信号处理.在阶段完成后,将此功能作为后台任务运行的调用方负责向其发送信号.

当然,还有一些基本的测试用例可以证明这一点.首先,我们需要确保退出时杀死运行backgroundReporter()的子进程.当它不运行时执行以下命令:(一个简单的no-op)并杀死-HUP< pid>.运行时:

killCmd=":" ; trap "${killCmd}" EXIT

然后,我们报告初始进度为零,并开始三个阶段.它们比此处指定的问题短,因为这仅用于演示目的:

doProg 0

# 0 -> 10% at 4%/sec, phase takes six seconds.
bgReport 0 10 4 1 & killCmd="kill -HUP $!" ; sleep 6 ; ${killCmd} ; killCmd=":" ; wait

# 10 -> 20% at 1%/2secs, phase takes six seconds.
bgReport 10 20 1 2 & killCmd="kill -HUP $!" ; sleep 6 ; ${killCmd} ; killCmd=":" ; wait

# 20 -> 100% at 30%/sec, phase takes five seconds.
bgReport 20 100 30 1 & killCmd="kill -HUP $!" ; sleep 5 ; ${killCmd} ; killCmd=":" ; wait

而且,从样本运行中您可以看到,这三个阶段的工作非常符合您的期望(右边的评论是我的):

13:15:29: 0%
13:15:30: 4%      4% per sec
13:15:31: 8%
13:15:32: 10%     capped at 10% for remainder of 6-sec slot

13:15:37: 11%     goes up 1% per 2 secs
13:15:39: 12%
13:15:41: 20%     phase finishes, jumps immediately to max

13:15:42: 50%     goes up 30% per second
13:15:43: 80%
13:15:44: 100%    but capped at 100%

对于给定的实际时间,两分钟,其中阶段是5%的最终验证,45%的最终拆包和90%的最终安装,以下比较合适(阶段稍作修改,使比例更容易实现):

doProg 0

# Validation 0 -> 5%, 5 steps in 6 seconds (~ 1%/1s).
bgReport 0 5 1 1 & killCmd="kill -HUP $!"
validate
${killCmd} ; killCmd=":" ; wait

# Unpacking 5 -> 45%, 40 steps in 50 seconds (4%/5s).
bgReport 5 45 4 5 & killCmd="kill -HUP $!"
unpack
${killCmd} ; killCmd=":" ; wait

# Installing 45 -> 95%, 50 steps in 64 seconds (~ 5%/6s)
bgReport 45 95 5 6 & killCmd="kill -HUP $!"
install
${killCmd} ; killCmd=":" ; wait

有了这些比率,您可以保证每(最多)六秒钟获得一次进度更新,这与原始方法不同,原始方法是将其停留在45%的状态持续一分钟,然后立即跳至95%.

上一篇:php exec如何查看进度


下一篇:java-可能禁用秋千的进度条?