shell进度条追踪指令执行时间
农民工老王 人气:0最近一两年,我经手了不少与shell相关的工作。在这个过程中,我越发觉得shell脚本在完成具体任务的同时,应该再给用户展示一个进度条,用以提示当前阶段还需要多少时间才能完成。
linux中的不少软件都有进度条,比如yum的软件安装过程,docker的镜像拉取过程。本想借鉴这些软件的进度条的实现方法,但其开发语言大都不是shell,我就只好作罢。随后,我在网上搜索shell进度条的实现方法,而找到的大都是用for或while循环在控制台上直接打印等号或箭头,并在循环体中用sleep命令实现一个固定的停顿,因而进度条完成的时间是固定的,而且在打印进度条时也没有实现具体任务。那种进度条是完全没有意义的。
于是,我就自己实现了一个shell进度条,测试表明实现了既定目标。可以追踪指令的执行时间。如果在预定用时之前完成,那么进度条会接到通知,然后立刻跑完剩余进度;如果指令的运行用时超出预定时间,那么进度条会在96%的地方等待指令跟上,然后再跑完剩余的4%。
本文中的进度条可以应用于大部分场景。不用修改进度条函数的任何代码,就可以直接使用。特别适合那些可预估指令执行时间的场景。对于如下载、文件复制等可以准确地计算出进度数值的情况,也可以基本满足,还可以参考本文的思路,修改进度条函数,进而显示精确的进度数值。
代码
代码如下:
#!/bin/bash progressBarTempPath=$(mktemp) echo "0" >"$progressBarTempPath" progressBar () { local time=$1 local interval=1 if [[ "${time}" == *"s" ]]; then interval=$(echo "scale=5;${time//s/}/60"|bc) elif [[ "${time}" == *"m" ]]; then interval=${time//m/} else echo "进度条参数错误" return 1 fi local nowNum=1 local str='' local postfix=('/' '-' '\' '|') while [ $nowNum -le 100 ]; do local needEnd=`cat "$progressBarTempPath"` local index=$((nowNum%4)) printf "[%-50s %-3d%% %c]\r" "$str" "$nowNum" "${postfix[$index]}" nowNum=$((nowNum+1)) if [ $needEnd -eq 1 ]; then sleep 0.1 else if [ $nowNum -le 20 ] ; then sleep $interval elif [ $nowNum -gt 95 ];then local nowNumCopy=$nowNum while [ $needEnd -eq 0 ]; do sleep $interval local innerIndex=$(((nowNumCopy+1)%4)) printf "[%-50s %-3d%% %c]\r" "$str" "$nowNum" "${postfix[$innerIndex]} " needEnd=$(cat "$progressBarTempPath") nowNumCopy=$((nowNumCopy+1)) done else sleep $(echo "scale=5;${interval}/2"|bc) fi fi if (($nowNum % 2 == 0)); then str+='=' fi done printf "\n" } # 多线程调用进度条函数,参数表示预估的大概时间。参数中的s表示时间单位秒,还可以用m表分钟。 progressBar 20s & # 调用进度条后,就是完成具体操作的代码。 echo "模拟一个24秒执行完成的任务。" sleep 24 # 通知进度条函数完成进度 echo "1" >"$progressBarTempPath" wait
使用说明
使用非常简单,按照以下两步操作即可。
- 将代码中的第56、57行换成您实际需要执行的命令。最好屏蔽其运行过程中的输出。
- 将代码中第53行的方法调用参数
20s
换成你预估的实际时间。
效果展示
加载全部内容