progress bar

progress bar

Tutorial

win_batch_progress_bar_test.bat

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
@echo off

:: ---------------------------------------------------------------------------------------------------------------------------------------------
:: Main
setlocal enableextensions disabledelayedexpansion

call :drawProgressBar 10 "status 1"
call :waitFor 1000
echo.

call :drawProgressBar 20 "status 2"
call :waitFor 1000
echo.

call :drawProgressBar 30 "status 3"
call :waitFor 1000
echo.

for /l %%f in (0 1 100) do (
call :drawProgressBar %%f "up test with a long text that will not fit on screen unless you have a lot of space"
call :waitFor 20
)
echo.

for /l %%f in (100 -1 0) do (
call :drawProgressBar %%f "going down test"
call :waitFor 20
)
echo.

for /l %%f in (0 5 100) do (
call :drawProgressBar !random! "random test"
call :waitFor 20
)
echo.

:: Clean all after use
call :finalizeProgressBar 1

call :initProgressBar "|" " "
call :drawProgressBar 0 "this is a custom progress bar"
for /l %%f in (0 1 100) do (
call :drawProgressBar %%f
call :waitFor 20
)
echo.

endlocal
exit /b

:: ---------------------------------------------------------------------------------------------------------------------------------------------
:: Functions
:drawProgressBar value [text]
if "%~1"=="" goto :eof
if not defined pb.barArea call :initProgressBar
setlocal enableextensions enabledelayedexpansion
set /a "pb.value=%~1 %% 101", "pb.filled=pb.value*pb.barArea/100", "pb.dotted=pb.barArea-pb.filled", "pb.pct=1000+pb.value"
set "pb.pct=%pb.pct:~-3%"
if "%~2"=="" ( set "pb.text=" ) else (
set "pb.text=%~2%pb.back%"
set "pb.text=!pb.text:~0,%pb.textArea%!"
)
<nul set /p "pb.prompt=[!pb.fill:~0,%pb.filled%!!pb.dots:~0,%pb.dotted%!][ %pb.pct% ] %pb.text%!pb.cr!"
endlocal
goto :eof

:initProgressBar [fillChar] [dotChar]
if defined pb.cr call :finalizeProgressBar
for /f %%a in ('copy "%~f0" nul /z') do set "pb.cr=%%a"
if "%~1"=="" ( set "pb.fillChar=#" ) else ( set "pb.fillChar=%~1" )
if "%~2"=="" ( set "pb.dotChar=." ) else ( set "pb.dotChar=%~2" )
set "pb.console.columns="
for /f "tokens=2 skip=4" %%f in ('mode con') do if not defined pb.console.columns set "pb.console.columns=%%f"
set /a "pb.barArea=pb.console.columns/2-2", "pb.textArea=pb.barArea-9"
set "pb.fill="
setlocal enableextensions enabledelayedexpansion
for /l %%p in (1 1 %pb.barArea%) do set "pb.fill=!pb.fill!%pb.fillChar%"
set "pb.fill=!pb.fill:~0,%pb.barArea%!"
set "pb.dots=!pb.fill:%pb.fillChar%=%pb.dotChar%!"
set "pb.back=!pb.fill:~0,%pb.textArea%!
set "pb.back=!pb.back:%pb.fillChar%= !"
endlocal & set "pb.fill=%pb.fill%" & set "pb.dots=%pb.dots%" & set "pb.back=%pb.back%"
goto :eof

:finalizeProgressBar [erase]
if defined pb.cr (
if not "%~1"=="" (
setlocal enabledelayedexpansion
set "pb.back="
for /l %%p in (1 1 %pb.console.columns%) do set "pb.back=!pb.back! "
<nul set /p "pb.prompt=!pb.cr!!pb.back:~1!!pb.cr!"
endlocal
)
)
for /f "tokens=1 delims==" %%v in ('set pb.') do set "%%v="
goto :eof

:waitFor
setlocal enabledelayedexpansion
set "sleepFor=%~1"

call :currentTime startTime
:: Note, dont use a for loop, the cmd prompt would try to expand each iteration, and that is a big problem
:loopStart
call :currentTime curTime
call :getTimeDiff result !startTime! !curTime!

set /A timeDiffMs=!result!*10
if !timeDiffMs! GTR !sleepFor! ( goto :return )

set /A timeRemaining=!sleepFor!-!timeDiffMs!
if !timeRemaining! GTR 1200 ( timeout /nobreak /t 1 >nul 2>&1 )
goto :loopStart

:return
endlocal
goto :eof

:currentTime
setlocal
set "curTime=%TIME%"
:: For some stupid reason if the hour < 10, it uses a blank space instead of a leading zero
if [^%curTime:~0,1%]==[^ ] set "curTime=0%curTime:~1%"
endlocal & set %~1=%curTime%
goto :eof

:getTimeDiff
setlocal
set "startTime=%~2"
set "endTime=%~3"

set /A startTime=(1%startTime:~0,2%-100)*360000 + (1%startTime:~3,2%-100)*6000 + (1%startTime:~6,2%-100)*100 + (1%startTime:~9,2%-100)
set /A endTime=(1%endTime:~0,2%-100)*360000 + (1%endTime:~3,2%-100)*6000 + (1%endTime:~6,2%-100)*100 + (1%endTime:~9,2%-100)
set /A duration=%endTime%-%startTime%
if %endTime% LSS %startTime% set set /A duration=%startTime%-%endTime%
endlocal & set "%~1=%duration%"
goto :eof

Result

progress_bar

Reference

stackoverflow progress_bar
Waiting (or “sleeping”) in a batch file

Author

Meow Lucian

Posted on

2022-09-14

Updated on

2022-09-14

Licensed under

Comments