Batch File progress spinning wheel - windows

I have been trying for days and can seem to get this to work. I found an example but it uses a (CryEcho) which will not work. I just wanted to add this to let the user know something is going on while im pinging IP addresses. I did find some code on here but it was confusing to me since im just starting to mess around with batch files for fun.
Anyway, I wanted to have something that used something like the example below but with text like (Waiting...[spinner]). Thanks!
#echo off
setlocal
set COUNT=0
set MAXCOUNT=10
set SECONDS=1
:LOOP
title "\"
call :WAIT
title "|"
call :WAIT
title "/"
call :WAIT
title "-"
if /i "%COUNT%" equ "%MAXCOUNT%" goto :EXIT
set /a count+=1
echo %COUNT%
goto :LOOP
:WAIT
ping -n %SECONDS% 127.0.0.1 > nul
ping -n %SECONDS% 127.0.0.1 > nul
goto :EOF
:EXIT
title FIN!
endlocal
AND I found this code as well:
#echo off
rem Example showing how to use CryEcho to produce a spinning wheel to show activity.
CryEcho Working ...
call :DoSomeWork
call :SpinAlive
call :DoSomeWork
call :SpinAlive
call :DoSomeWork
call :SpinAlive
call :DoSomeWork
call :SpinAlive
call :DoSomeWork
call :SpinAlive
call :DoSomeWork
call :SpinAlive
call :DoSomeWork
call :SpinAlive
call :DoSomeWork
call :SpinAlive
call :DoSomeWork
cryecho \s\nFinished.
goto :eof
:DoSomeWork
ping -n 1 localhost > nul
goto :eof
:SpinAlive
if "%Spinner%" == "2" (cryecho \\\b)
if "%Spinner%" == "3" (cryecho -q "|"\b)
if "%Spinner%" == "4" (cryecho /\b set Spinner=0) else (cryecho -\b set Spinner=1)
set /A Spinner=%Spinner%+1
goto :eof

The main trick is here to move the cursor back on the same line.
This can be done with a carriage return or a backspace characters.
#echo off
setlocal EnableDelayedExpansion
for /f %%a in ('copy /Z "%~dpf0" nul') do set "CR=%%a"
FOR /L %%n in (1,1,10) DO (
call :spinner
ping localhost -n 2 > nul
)
exit /b
:spinner
set /a "spinner=(spinner + 1) %% 4"
set "spinChars=\|/-"
<nul set /p ".=Waiting !spinChars:~%spinner%,1!!CR!"
exit /b
The <CR> character is created from the output of copy /z.
The output is done by set /p, as this omits the output of CR/LF at the end.
The !CR! is output each time to force the cursor to move back to the first column.
But as Win7 and Vista removes all whitespaces and also CR from the leading output of set /p, it's placed at the end.

#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
CALL :BACKSPACE $BS
SET /A FULL_COUNT=75
SET /A MAX_COUNT=160
SET /A Spin_Delay=60
SET "_MSG=Process running..."
SET /A CTR=0
IF NOT [%1]==[] SET "_MSG=%~1"
IF NOT [%2]==[] SET /A FULL_COUNT=%2
IF NOT [%3]==[] SET /A SPIN_DELAY=%3
IF %FULL_COUNT% GTR %MAX_COUNT% SET /A FULL_COUNT=%MAX_COUNT%
<nul SET/P="%_MSG%*"
SET "SPINNER=³/Ä\"
FOR /L %%A IN (1,1,%FULL_COUNT%) DO (
CALL :DELAY %SPIN_DELAY%
<nul CALL SET/P="%$BS%%%SPINNER:~!CTR!,1%%"
SET /A CTR=%%A %% 4
)
<nul SET/P="%$BS%*"
ENDLOCAL & EXIT /B %CTR%
:BackSpace
setlocal
for /f %%a in ('"prompt $H&for %%b in (1) do rem"') do set "BS=%%a"
endlocal&call set %~1=%BS%&exit /b 0
:Delay msec
setlocal
set/a correct=0
set/a msecs=%1+5
if /i %msecs% leq 20 set /a correct-=2
set time1=%time: =%
set/a tsecs=%1/1000 2>nul
set/a msecs=(%msecs% %% 1000)/10
for /f "tokens=1-4 delims=:." %%a in ("%time1%") do (
set hour1=%%a&set min1=%%b&set sec1=%%c&set "mil1=%%d"
)
if /i %hour1:~0,1% equ 0 if /i "%hour1:~1%" neq "" set hour1=%hour1:~1%
if /i %min1:~0,1% equ 0 set min1=%min1:~1%
if /i %sec1:~0,1% equ 0 set sec1=%sec1:~1%
if /i %mil1:~0,1% equ 0 set mil1=%mil1:~1%
set/a sec1+=(%hour1%*3600)+(%min1%*60)
set/a msecs+=%mil1%
set/a tsecs+=(%sec1%+%msecs%/100)
set/a msecs=%msecs% %% 100
:: check for midnight crossing
if /i %tsecs% geq 86400 set /a tsecs-=86400
set/a hour2=%tsecs% / 3600
set/a min2=(%tsecs%-(%hour2%*3600)) / 60
set/a sec2=(%tsecs%-(%hour2%*3600)) %% 60
set/a err=%msecs%
if /i %msecs% neq 0 set /a msecs+=%correct%
if /i 1%msecs% lss 20 set "msecs=0%msecs%"
if /i 1%min2% lss 20 set "min2=0%min2%"
if /i 1%sec2% lss 20 set "sec2=0%sec2%"
set "time2=%hour2%:%min2%:%sec2%.%msecs%"
:wait
set timen=%time: =%
if /i %timen% geq %time2% goto :end
goto :wait
:end
for /f "tokens=2 delims=." %%a in ("%timen%") do set num=%%a
if /i %num:~0,1% equ 0 set num=%num:~1%
set/a err=(%num%-%err%)*10
endlocal&exit /b %err%

Related

Coding two real time progress bars in batch

I really like the progress bar that #MCND coded in this post - Coding a real time progress bar in batch
Is there any way to add a second real-time progress bar just below the first one which could be manipulated seperately showing the overall progress of the batch file, while the first progress bar shows the real-time progress of the current function?
I tried copying the :drawProgressBar, :initProgressBar and :finalizeProgressBar subroutines and adding a 1 to the end of them and all pb variables in the subroutines to create a distinct subroutine, but no luck.
#MCND 's original post/code:
Just a skelleton. Adapt as needed.
The basic idea is to output the line with the progress bar with an ending carriage return to return to the start of the line and be able to repaint the next state over the previous one.
All "problematic" code wrapped into subroutines so you only need to call :drawProgressBar percentValue "operationText"
#echo off
setlocal enableextensions disabledelayedexpansion
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"
)
for /l %%f in (100 -1 0) do (
call :drawProgressBar %%f "going down test"
)
for /l %%f in (0 5 100) do (
call :drawProgressBar !random! "random test"
)
rem 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
)
endlocal
exit /b
: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

Running a cmd .bat file with loops and conditions

Hi I am trying to run a scrapy spider using start command from a cmd batch file. I want to run the spider parallely for 10 names from a csv file which contains more than 500 names. So my thought is to basically add some conditions in the loop from 1 to 500 that checks if the 10 command windows have closed, if not then wait for them to close (they auto close after spider is finished). Once the 10 windows which had opened, are closed, open the next 10 and so on. Following is the code I have, i am pretty sure it has big syntax errors. Could you help me debug? Thanks
cd /d "C:\Users\xyz"
for /f "tokens=1,*" %%m in ('tasklist ^| find /I /C "conhost.exe"') do (set var1=%%m)
set counter=1
for /f "usebackq tokens=1 delims=," %%n in ("test.csv") do (
(START /MIN "" scrapy crawl xyz_scraper -a query="%%n" -a pages=20)
set /a counter=counter+1
for /f "tokens=1,*" %%p in ('tasklist ^| find /I /C "conhost.exe"') do (set var2=%%p)
SET /A _result=counter%%10
echo %_result%
IF _result EQU 0 (
:abcd
timeout /t 10
if var2 EQU var1 (
goto bcde
)
ELSE (
goto abcd)
)
:bcde
)
pause
EDIT: deleted the for loop one. Edited the above code based on some suggestions. I don't understand where would i use quotes for variables and where not and how to print a variables value to cmd.
The updated code below:
cd /d "C:\Users\sodhian\sodhi-scraper"
for /f "tokens=1,*" %%m in ('tasklist ^| find /I /C "conhost.exe"') do (set var1=%%m)
echo %var1%
set counter=1
for /f "usebackq tokens=1 delims=," %%n in ("test comp.csv") do (
(START /MIN "" scrapy crawl ind_scraper -a query="%%n" -a pages=20)
set /a "counter=counter+1"
echo %counter%
SET /A _result="counter%%2"
echo %_result%
IF "%_result%" EQU "0" (
:abcd
timeout /t 10
for /f "tokens=1,*" %%p in ('tasklist ^| find /I /C "conhost.exe"') do (set var2=%%p)
echo %var2%
if var2==var1 (
goto bcde
)
ELSE (
goto abcd)
)
:bcde
)
pause
Edit 2:
Based on Stephan's answer. Tried to accomplish what i mentioned in comment of the answer:
setlocal enabledelayedexpansion
set counter=0
for /f "usebackq tokens=1 delims=," %%n in ("test comp.csv") do (
set /a counter+=1
start /MIN "MySpider!counter!" scrapy crawl ind_scraper -a query="%%n" -a pages=20
for /f "tokens=1,*" %%b in ('tasklist /v ^| find /I /C "MySpider"') do (set var1=%%b)
if !var1! geq 5 call :wait
)
:wait
timeout /t 5
for /f "tokens=1,*" %%p in ('tasklist /v ^| find /I /C "MySpider"') do (set var2=%%p)
if !var2! geq 5 call :wait
goto :eof
Changed it to the following: (the /v (verbose option in tasklist was making the above slow)
setlocal enabledelayedexpansion
set counter=0
set max_scrappers=7
for /f "tokens=1,*" %%a in ('tasklist ^| find /C "conhost"') do (set var1=%%a)
for /f "usebackq tokens=1 delims=," %%n in ("test comp.csv") do (
set /a counter+=1
start /min "MySpider!counter!" scrapy crawl ind_scraper -a query="%%n" -a pages=20
for /f "tokens=1,*" %%b in ('tasklist ^| find /C "conhost"') do (set var2=%%b)
set /a var3=!var2!-!var1!
if !var3! geq !max_scrappers! call :wait
)
:wait
for /f "tokens=1,*" %%p in ('tasklist ^| find /C "conhost"') do (set var4=%%p)
set /a var5=!var4!-!var1!
if !var5! geq !max_scrappers! call :wait
goto :eof
As already noted in the comments, labels inside a code block don't work. But you can call a "function", where goto and labels are no problem:
I choosed other numbers and another command to make it work on every system (and faster). Replacing the timeout command with your spider and adapting the numbers should be no problem.
#echo off
setlocal enabledelayedexpansion
REM next line just for generating a testfile:
>"test comp.csv" (for /l %%i in (1,1,10) do echo !random:~-1!)
set counter=0
for /f "usebackq tokens=1 delims=," %%n in ("test comp.csv") do (
set /a counter+=1
start "MySpider!counter!" timeout %%n
if !counter! geq 3 call :wait
)
:wait
tasklist /v|find "MySpider">nul && goto :wait
set counter=0
goto :eof
Searching for conhost is not a good idea, because there could be other processes. Choose an unique window title instead (MySpider in my example) and look for that title (tasklist /v)

BATCH- binary with for

I have to make a script that has to calculate the mask and the net, so I'm trying a script with for but it can not convert the IP to binary. I think I'm not using the variables right.
Any ideas?
#echo off
setlocal enabledelayedexpansion
set var=%1
set /p var=Introduce la ip:
for /F "tokens=1 delims=." %%a in ("%var%") do (
echo %%a
set "vara=%%a"
:binario
set bin=2
set /a resto=%vara%%%bin%
set /a a=%vara%/%bin%
set resultado=%resto%%resultado%
if %vara% GTR 0 (goto binario)
echo %resultado%
goto siguiente
)
:siguiente
for /F "tokens=2 delims=." %%b in ("%var%") do (
echo %%b
)
for /F "tokens=3 delims=." %%c in ("%var%") do (
echo %%c
)
for /F "tokens=4 delims=." %%d in ("%var%") do (
echo %%d
)
goto fin
:vacio
echo Error!
goto fin
:fin
pause
You've got a few minor problems that I see. You set var=%1 but you never check to see whether %1 was supplied before doing set /p var=Enter an IP:. You never call or goto :vacio. As I commented above, modulos within batch scripts need to be written as %% to prevent evaluation as variable chararacters. You don't need % in var names in set /a commands, and you can combine multiple set /a statements with a comma. So instead of
set /a resto=%vara%%%bin%
set /a a=%vara%/%bin%
(which is wrong anyway -- I'll get to that in a minute), I suggest this would be more understandable and maintainable:
set /a resto = vara %% bin, numero = vara / bin
The biggest problem is that you appear to be trying to modify %%a. Don't do that.
If I were you, I would move the decimal to binary conversion to a subroutine, and call it for each octet. Try this:
#echo off
setlocal enabledelayedexpansion
set IP=%1
if "%IP%"=="" set /p "IP=Introduce la ip: "
set idx=0
for %%a in (%IP:.= %) do (
if %%a lss 0 goto vacio
if %%a gtr 255 goto vacio
if !idx! gtr 3 goto vacio
set /P "=%%a = "<NUL
call :dec2bin bin[!idx!] %%a
set /a idx += 1
)
echo %bin[0]%.%bin[1]%.%bin[2]%.%bin[3]%
goto fin
:dec2bin <var_para_definir> <numero>
setlocal enabledelayedexpansion
set numero=%~2
set bin=
for /L %%I in (1,1,8) do (
set /a bit = numero %% 2, numero /= 2
set bin=!bit!!bin!
)
echo %bin%
endlocal & set "%~1=%bin%"
goto :EOF
:vacio
echo Error!
goto fin
:fin
pause
For more information about using call as a function that returns a value, see this page.

batch variable string manipulation not working

Here's my code, (i tried to make a progress bar but failed).
#echo off & setlocal enabledelayedexpansion
set bar=**********
set cnt=0
:LOOP
cls
set /A cnt+=1
echo.Progress:!bar:~0,%cnt%!
ping -n 1 www.google.com > nul 2>&1
if "%cnt%" NEQ 10 goto :LOOP
echo.finished.
pause > nul
exit /b
I get this as output:
bar:~0,1
bar:~0,2
bar:~0,3
etc.. etc..
I want it to go like:*, **, *** etc.. basically increase the asterisk by 1 every second.
try this:
#echo off & setlocal enabledelayedexpansion
set "bar=**********"
set /a cnt=0
:LOOP
cls
set /A cnt+=1
SET "progressbar=!bar:~0,%cnt%!"
ECHO(Progress:%progressbar%
ping -n 1 www.google.com > nul 2>&1
if %cnt% NEQ 10 goto :LOOP
ECHO(finished.
REM example without CLS
<NUL set/p "=Progress:"
:LOOPING
<NUL set/p"=*"
ping -n 1 www.google.com > nul 2>&1
SET /a count+=1
if %count% NEQ 10 goto :LOOPING
ECHO(&ECHO(finished.

Search By Seconds Not Minutes

I have a batch file that works pretty well. I originaly set it up to search for files that are a minute or less old. I need to go down further and search for files that are 15 seconds old. I hope thats quick enough, I might have to adjust it later. In any case can anyone help me get it down to the seconds range. Thank you. Your help is appreciated.
#echo off
cd "C:\Users\DS\Downloads"
setlocal
call :DateToMinutes %date:~-4% %date:~-10,2% %date:~-7,2% %time:~0,2% %time:~3,2% NowMins
set flag=0
for /f "delims=" %%a in ('dir *.jpg *.zip *.txt /a-d /b') do call :CheckMins "%%a" "%%~ta"
if %flag% EQU 1 (
msg * "Good-Bye!"
)
set flag=0
goto :EOF
:CheckMins
set File=%1
set TimeStamp=%2
call :DateToMinutes %timestamp:~7,4% %timestamp:~1,2% %timestamp:~4,2% %timestamp:~12,2% %timestamp:~15,2%%timestamp:~18,1% FileMins
set /a MinsOld=%NowMins%-%FileMins%
if %MinsOld% leq 1 del %file%
if %MinsOld% leq 1 set flag=1
goto :EOF
:DateToMinutes
setlocal
set yy=%1&set mm=%2&set dd=%3&set hh=%4&set nn=%5
if 1%yy% LSS 200 if 1%yy% LSS 170 (set yy=20%yy%) else (set yy=19%yy%)
set /a dd=100%dd%%%100,mm=100%mm%%%100
set /a z=14-mm,z/=12,y=yy+4800-z,m=mm+12*z-3,j=153*m+2
set /a j=j/5+dd+y*365+y/4-y/100+y/400-2472633
if 1%hh% LSS 20 set hh=0%hh%
if /i {%nn:~2,1%} EQU {p} if "%hh%" NEQ "12" set hh=1%hh%&set/a hh-=88
if /i {%nn:~2,1%} EQU {a} if "%hh%" EQU "12" set hh=00
if /i {%nn:~2,1%} GEQ {a} set nn=%nn:~0,2%
set /a hh=100%hh%%%100,nn=100%nn%%%100,j=j*1440+hh*60+nn
endlocal&set %6=%j%&goto :EOF
I didn't know a simple batch way to get the seconds, but you can get them via WMIC.
WMIC DATAFILE WHERE Name="C:\\windows\\DirectX.log" GET lastmodified,Lastaccessed
The format of the output is a bit odd, but it should work.

Resources