Variables not incrementing within a batch file - batch-file

So I am trying to create a file that will read a text file called saves. In saves I want it to check up to 5 time for 1:, 2:, 3: ,4:, and 5:. The issue is that when I run this for loop to check the file 5 times it always outputs the same thing and no matter what will say there are no saves. Any help or advice is much appreciated.
#ECHO off
SETLOCAL EnableDelayedExpansion
SET test=0
FOR /L %%i IN (1,1,5) DO (
FINDSTR %%i: Saves.txt >NUL && SET /a %test%+1
ECHO %test%
)
IF %test% EQU 0 ECHO There are no saves. & GOTO :end
IF %test% GTR 0 ECHO There are saves.
:END
PAUSE

You are not using the SET command correctly and you need to use delayed expansion to display the variable correctly when inside a parenthesized code block.
#ECHO off
SETLOCAL EnableDelayedExpansion
SET test=0
FOR /L %%i IN (1,1,5) DO (
FINDSTR /B %%i: Saves.txt >NUL && SET /a test+=1
ECHO !test!
)
IF %test% EQU 0 ECHO There are no saves. & GOTO :end
IF %test% GTR 0 ECHO There are saves.
:END
PAUSE
An easier option would be.
FINDSTR /B "1: 2: 3: 4: 5:" Saves.txt >NUL 2>&1 && (ECHO There are saves.) || (ECHO There are no saves.)
If all your lines begin with a number and colon then you can just do this.
FOR /F "tokens=1 delims=:" %%G IN (saves.txt) do set numsaves=%%G

Related

Batch script to check the content and file name

I have a code in batch script which will check if the name of the file is same or content of the file is same or not. Also it will updat the ini file to 0 or 1
0 - if the file names are different
1 - if the file names are different
Below is my code
#ECHO OFF
CLS
del /s C:\deep\output.log > NUL
for %%i in (C:\deep\*.DAT) do (
for /f "tokens=1,2 delims= " %%G in (app.ini) do set %%G=%%H
echo Rungmis %rungmis%
fc C:\deep\MAI_ZSYS_MOVE.DAT %%i > NUL
if errorlevel 1 (
CALL :error
echo C:\deep\MAI_ZSYS_MOVE.DAT and %%i are different >>output.log
set /a rungmis=0
echo Rungmis %rungmis%
timeout 5
) ELSE (
CALL :next
echo C:\deep\MAI_ZSYS_MOVE.DAT and %%i are same >>output.log
set /a rungmis=1
echo Rungmis %rungmis%
timeout 5
)
)
for %%I in (rungmis) do (
setlocal enabledelayedexpansion
type app.ini | find /v "%%I=">settings.tmp
move /y settings.tmp gmisapp.ini
echo %%I=!%%I!>>app.ini
)
type app.ini
timeout 5
It is updating the .ini flag (rungmis flag) to 0 or 1. But the problem which i am facing is whenever the ini is getting updated the flag (rungmis) is getting updated at the last line of the ini
Actual app.ini file
[TO_RUN_GMIS]
rungmis=1
;0 means GMIS will run
;1 means GMIS will not run
[Registry_Directories]
ArchivePath=D:\maibackup\
ImportPath=D:\gmisdata\
ExportPath=D:\www\GMIS\excel\
DataSource=GMIS_DEV_NEW
app.ini after getting updated
[TO_RUN_GMIS]
;0 means GMIS will run
;1 means GMIS will not run
[Registry_Directories]
ArchivePath=D:\maibackup\
ImportPath=D:\gmisdata\
ExportPath=D:\www\GMIS\excel\
rungmis=1
can anyone please help me out with that?
Please give this a try.
#ECHO OFF
CLS
del /s C:\deep\output.log > NUL
for %%i in (C:\deep\*.DAT) do (
for /f "tokens=1,2 delims= " %%G in (app.ini) do set %%G=%%H
echo Rungmis %rungmis%
fc C:\deep\MAI_ZSYS_MOVE.DAT %%i > NUL
if errorlevel 1 (
CALL :error
echo C:\deep\MAI_ZSYS_MOVE.DAT and %%i are different >>output.log
set /a rungmis=0
echo Rungmis %rungmis%
timeout 5
) ELSE (
CALL :next
echo C:\deep\MAI_ZSYS_MOVE.DAT and %%i are same >>output.log
set /a rungmis=1
echo Rungmis %rungmis%
timeout 5
)
)
for /f "tokens=*" %%a in ('type "app.ini" ^| find /v /n "" ^& break ^> "app.ini"') do (
set "str=%%a"
setlocal enabledelayedexpansion
set "str=!str:*]=!"
if "!str:~0,7!"=="rungmis" set "str=!str:~0,-1!%rungmis%"
>>app.ini echo(!str!
endlocal
)
type app.ini
timeout 5
So we simply do a type on the file and add some additional characters to ensure we replicate newlines as well. We then get rid of those characters before printing to file. But first we search for the string rungmis and replaces its value with the value you determined earlier in the script. Then each line gets printed back into the app.ini file with the replacement value.

Variable outside for /f command keeps getting reset

In the following code, it seems that the set /A lcnt=3 at the top of the file is executed each time that the for /f command just below the REM #1 is executed.
I guess I don't understand the flow of execution. I thought it just runs from top to bottom, barring any gotos.
My script:
echo off
REm Why is the following set command executed each time
REM in the below "processToken section"?
set /A lcnt=3
cd c:\download
REM ___ input file _____
REm Moe Larry Curly
REM Manny Moe Jack
REM ___ echo output ____
REM 4
REM 3
REM 5
REM 4
REM 6
REM 5
REM 4
REM 3
REM 5
REM 4
REM 6
REM 5
REm #1
for /f "tokens=* delims= " %%f in ('type test_list.txt') do (
set line=%%f
call :processToken
)
pause
goto :eof
:processToken
SETLOCAL EnableDelayedExpansion
for /f "tokens=1* delims= " %%a in ("%line%") do (
set /A lcnt+=1
echo !lcnt!
echo %lcnt%
set line=%%b
)
if not "%line%" == "" goto :processToken
goto :eof
pause
I'm not sure what you're trying to achieve because your question does not provide that information.
Here therefore is some example code which may help:
#Echo Off
SetLocal EnableDelayedExpansion
Set "x=0"
For /F "UseBackQDelims=" %%A in ("C:\download\test_list.txt") Do (Set/A x+=1
Set "y=0"
For %%B In (%%A) Do (Set/A y+=1
Set "line!x!str!y!=%%~B")
Echo line!x! has !y! space separated strings)
Set line 2>Nul
Pause

How can we split string using windows bat

How can we split string using windows bat script?
for below .bat code snippet
#echo off & setlocal EnableDelayedExpansion
set j=0
for /f "delims=""" %%i in (config.ini) do (
set /a j+=1
set con!j!=%%i
call set a=%%con!j!%%
echo !a!
(echo !a!|findstr "^#">nul 2>nul && (
rem mkdir !a!
) || (
echo +)
rem for /f "tokens=2" %%k in(config.ini) do echo %%k
)
)
pause
below config file
Q
What's wrong when I del rem at the begin of rem for /f "tokens=2" %%k in(config.ini) do echo %%k
How can I get the /path/to/case and value as a pair?
for /f xxxx in (testconfig.ini) do (set a=/path/to/case1 set b=vaule1)
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET "sourcedir=U:\sourcedir"
SET "filename1=%sourcedir%\q43407067.txt"
set j=0
for /f "delims=""" %%i in (%filename1%) do (
set /a j+=1
set con!j!=%%i
call set a=%%con!j!%%
echo !a! SHOULD BE EQUAL TO %%i
(echo !a!|findstr "^#">nul 2>nul && (
echo mkdir !a!
) || (
echo +)
for /f "tokens=2" %%k IN ("%%i") do echo "%%k"
for /f "tokens=1,2" %%j IN ("%%i") do echo "%%j" and "%%k"
)
)
ECHO ----------------------------
SET con
GOTO :EOF
You would need to change the setting of sourcedir to suit your circumstances.
I used a file named q43407067.txt containing your data for my testing.
(These are setting that suit my system)
SO - to address your problems:
because the ) on that line closes the ( on the previous. The ) on that line closes the ( on the one prior. (I changed the rem to an echo so that the code would produce something visible) The first ( on the (echo !a! line is closed by the ) on the line following the (now) two for /f commands. and the ( on the for..%%i..do( is closed by the final ) before the echo -----
You can't delete that ) because it's participating in a parenthesis-pair.
You need a space between the in and the (.
I've shown a way. See for /?|more from the prompt for documentation (or many articles here on SO)
In your code, !a! is the same as %%i - so I've no idea why you are conducting all the gymnastics - doubtless to present a minimal example showing the problem.
Note that since the default delimiters include Space then if any line contains a space in the /path/to/case or value then you'll have to re-engineer the approach.
I' not sure if I understand what exactly it is you need, so what follows may not suit your needs:
#Echo Off
SetLocal EnableDelayedExpansion
Set "n=0"
For /F "Delims=" %%A In (testConfig.ini) Do (Set "_=%%A"
If "!_:~,1!"=="#" (Set/A "n+=1", "i=0"
Echo=MD %%A
Set "con[!n!]!i!=%%A") Else (For /F "Tokens=1-2" %%B In ('Echo=%%A'
) Do (Set/A "i+=1"
Set "con[!n!]!i!=%%B"&&Set/A "i+=1"&&Set "con[!n!]!i!=%%C")))
Set con[
Timeout -1
GoTo :EOF
remove Echo= on line 6 if you are happy with the output and really want to create those directories

Batch Script Substring from string

Ok, I have been playing around with this for a while and am getting no where. I need to pull the KB number out from a line.
The issue i am having is that some of the KB numbers are 6 characters and some are 7, and can't seem to find a way that will work to error detect the two.
The Two types of errors this makes is as follows
The First one should only have been displayed 6 characts so it added the extra "-" at the end.
x64 KB890830- 2012\MS12-000\WinSec-KB890830-006-P58310-Windows-KB890830-x64-V4.9.exe
While the second error shows the random "_" because it uses the first KB shown not the second.
ia64 KB_942288 2012\MS12-000\WinSec-KB_942288-007-P58312-WindowsServer2003-KB942288-v4-ia64.exe
EDIT
Batch File So Far
#ECHO OFF
SETLOCAL enableDelayedExpansion
IF EXIST Export.csv DEL Export.csv
FOR /F "tokens=*" %%I in ('dir /s /b *.*') DO CALl:Generate "%%I"
pause
:Generate
SETLOCAL
IF "%~x1" NEQ ".exe" (
If "%~x3" NEQ ".msu" (
GOTO:EOF
)
)
CALL:FindArchitecture %1
CALL:FindKB %1
CALL:PathFix %1
ECHO %Architecture%,%KB%,%FilePath%>>Export.csv
CALL:Cleanup
ENDLOCAL
GOTO:EOF
:FindArchitecture
ECHO %1 | FINDSTR "x64"
IF "%ERRORLEVEL%"=="0" (
SET Architecture=x64
SET Count+=1
)
ECHO %1 | FINDSTR "x86"
IF "%ERRORLEVEL%"=="0" (
SET Architecture=x86
SET Count+=1
)
ECHO %1 | FINDSTR "ia64"
IF "%ERRORLEVEL%"=="0" (
SET Architecture=ia64
SET Count+=1
)
IF "%Count%" GTR "1" (
SET Architecture=Error
)
SET Count=0
GOTO:EOF
:FindKB
set KBNum="%~1"
set "KBNum=!KBNum:*-KB=!"
ECHO !KBNum!|findstr /I /E /R /c:"-KB[0-9][0-9][0-9][0-9][0-9][0-9][0-9]" >nul
SET "KB=KB!KBNum:~0,7!"
IF "%KB%" NEQ "" GOTO:EOF
ECHO !KBNum!|findstr /I /E /r /c:"-KB[0-9][0-9][0-9][0-9][0-9][0-9]" >nul
SET "KB=KB!KBNum:~0,6!"
GOTO:EOF
:PathFix
set Path_to_convert=%~1
set Reference_path=%~dp0
set FilePath=!Path_to_convert:*%Reference_path%=!
GOTO:EOF
:Cleanup
SET KBNum=
SET KB=
SET Count=
SET Architecture=
set InstallerPath=
set PathRemoval=
set Path=
GOTO:EOF
OK - siginificant edit after seeing comments from Ken White and the OP.
I'm not sure if you need this, but FINDSTR with a regular expression can validate that the line has the pattern: "-KB" followed by 7 digits, followed by "-".
echo somestring|findstr /r /c:"-KB[0-9][0-9][0-9][0-9][0-9][0-9][0-9]-" >nul
Then use substitution to remove everything from the beginning through "KB-".
Then use FINDSTR to verify that the first 7 remaining characters are digits. If not, then loop back and replace up to the next "-KB", etc.
Then you just need to take the first remaining 7 characters.
#echo off
:parseVal
setlocal enableDelayedExpansion
set val="%~1"
echo !val!|findstr /r /c:"-KB[0-9][0-9][0-9][0-9][0-9][0-9][0-9]-" >nul || (
echo Invalid format - KB value not found
exit /b
)
:parseVal2
set "val=!val:*-KB=!"
echo !val!|findstr /brc:"[0-9][0-9][0-9][0-9][0-9][0-9][0-9]-" >nul || goto :parseVal2
set "val=KB!val:~0,7!"
echo val=!val!
exit /b
EDIT
I'm not sure what you did to accept the 6 digit numbers, but the following regex expressions will work with numbers of any length.
For the 1st regex: findstr /rc:"-KB[0-9]*-"
For the 2nd regex: findstr /brc:"[0-9]*-"
Then you can use either of the following to extract out the number when you don't know the length:
for /f "delims=-" %%A in ("!val!") do set "val=KB%%A"
or
set val=KB%val:-=&REM %"

How to code a spinner for waiting processes in a Batch file?

I would like to show the user with a spinner, that something is done in background but do not know how this works in a batchfile.
Does anyone have a clue?
This can actually be done quite easily with pure native commands, you just have to know how to use the more tricky of them. No use of external tools like VBScript or nasty side effects like clearing the screen are necessary.
What you're looking for is the equivalent of the bash "echo -n" command which outputs a line without the newline. In XP batch, this is achieved by using "set /p" (ask user for response with a prompt) with empty input as follows:
<nul (set /p junk=Hello)
echo. again.
will output the string "Hello again." with no intervening newline.
That trick (and the use of CTRL-H, the backspace character can be seen in the following test script which starts (one after the other) a 10-second sub-task with a 20-second timeout and a 15-second sub-task with a 10-second timeout.
The payload script is created by the actual running script and its only requirement is that it do the work it has to do then delete a flag file when finished, so that the monitor function will be able to detect it.
Keep in mind that the ^H strings in this script are actually CTRL-H characters, the ^| is two separate characters used to escape the pipe symbol.
#echo off
:: Localise environment.
setlocal enableextensions enabledelayedexpansion
:: Specify directories. Your current working directory is used
:: to create temporary files tmp_*.*
set wkdir=%~dp0%
set wkdir=%wkdir:~0,-1%
:: First pass, 10-second task with 20-second timeout.
del "%wkdir%\tmp_*.*" 2>nul
echo >>"%wkdir%\tmp_payload.cmd" ping 127.0.0.1 -n 11 ^>nul
echo >>"%wkdir%\tmp_payload.cmd" del "%wkdir%\tmp_payload.flg"
call :monitor "%wkdir%\tmp_payload.cmd" "%wkdir%\tmp_payload.flg" 20
:: Second pass, 15-second task with 10-second timeout.
del "%wkdir%\tmp_*.*" 2>nul:
echo >>"%wkdir%\tmp_payload.cmd" ping 127.0.0.1 -n 16 ^>nul
echo >>"%wkdir%\tmp_payload.cmd" del "%wkdir%\tmp_payload.flg"
call :monitor "%wkdir%\tmp_payload.cmd" "%wkdir%\tmp_payload.flg" 10
goto :final
:monitor
:: Create flag file and start the payload minimized.
echo >>%2 dummy
start /min cmd.exe /c "%1"
:: Start monitoring.
:: i is the indicator (0=|,1=/,2=-,3=\).
:: m is the number of seconds left before timeout.
set i=0
set m=%3
<nul (set /p z=Waiting for child to finish: ^|)
:: Loop here awaiting completion.
:loop
:: Wait one second.
ping 127.0.0.1 -n 2 >nul
:: Update counters and output progress indicator.
set /a "i = i + 1"
set /a "m = m - 1"
if %i% equ 4 set i=0
if %i% equ 0 <nul (set /p z=^H^|)
if %i% equ 1 <nul (set /p z=^H/)
if %i% equ 2 <nul (set /p z=^H-)
if %i% equ 3 <nul (set /p z=^H\)
:: End conditions, complete or timeout.
if not exist %2 (
echo.
echo. Complete.
goto :final
)
if %m% leq 0 (
echo.
echo. *** ERROR: Timed-out waiting for child.
goto :final
)
goto :loop
:final
endlocal
If you don't mind the screen clearing...try this:
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET COUNT=1
START CALC
:BEGIN
CLS
IF !COUNT! EQU 1 ECHO \
IF !COUNT! EQU 2 ECHO -
IF !COUNT! EQU 3 ECHO /
IF !COUNT! EQU 4 ECHO -
IF !COUNT! EQU 4 (
SET COUNT=1
) ELSE (
SET /A COUNT+=1
)
PSLIST CALC >nul 2>&1
IF %ERRORLEVEL% EQU 1 GOTO END
GOTO BEGIN
:END
EDIT: This sample will start Calculator and then display a "spinner" until you close Calculator. I use pslist to check for the existence of CALC.EXE. The >nul 2>&1 redirects STDOUT and STDERR to nul so nothing from PSLIST will be displayed.
Try this:
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
CALL :BACKSPACE $BS
SET /A FULL_COUNT=60
SET /A MAX_COUNT=160
SET /A Spin_Delay=50
SET "_MSG=Process running..."
SET /A CTR=0
SET /A TCT=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 FULL_COUNT=%MAX_COUNT%
(SET/P=%_MSG%*)<nul
FOR /L %%A IN (1,1,%FULL_COUNT%) DO (
CALL :DELAY %SPIN_DELAY%
IF !CTR! EQU 0 (set/p=%$BS%³)<nul
IF !CTR! EQU 1 (set/p=%$BS%/)<nul
IF !CTR! EQU 2 (set/p=%$BS%Ä)<nul
IF !CTR! EQU 3 (set/p=%$BS%\)<nul
SET /A CTR=%%A %% 4
)
(SET/P=%$BS%*)<nul
ENDLOCAL & EXIT /B %CTR%
:BackSpace
setlocal
for /f %%a in ('"prompt $H$S &echo on &for %%b in (1) do rem"') do set "Bs=%%a"
endlocal&call set %~1=%BS%&exit /b 0
:Delay msec
setlocal enableextensions
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%
If I understand your question you want a spinner because some operation you are performing is taking time and you want to show to the user that something is happening, right?
In that case, as far as I know, its not possible with the native commands. (it could be possible if you had a program that showed a spinner while executing the operation that take long time)
And it looks like the echo don't support ansi escape sequences (in the old days you had to have ansi.sys loaded, don't know if that still exists) so you can't use ansi to control the cursor.
The spinner CAN be done in batch script, you just need some variables:
#echo off
:spinner
set mSpinner=%mSpinner%.
if %mSpinner%'==..............................' set mSpinner=.
cls
echo %mSpinner%
rem Check if the process has finished via WMIC and/or tasklist.
goto spinner
:exit
For the BAT itself to detect a process running/exits. You can do that via the WMI command-line interface or the tasklist command of which I have limited knowledge.
If it were back in the DOS days you could even does that without clearing the screen... short of using some combination of escape characters. I don't know if it's still possible on Vista/XP.
If you mean within a Windows batch script, you can't do it natively. The echo statement used to print to the console will always print a newline, and you can't move the cursor.
It's a bit of a hack, but you can do this with a combination of VBScript and batch script.
This VBScript will print a backspace, then it's argument:
WScript.StdOut.Write(chr(8) & WScript.Arguments(0))
Put this in a file, vbsEcho.vbs, then call this script from your batch script. The following batch script will keep displaying the spinner until you press CTRL-C:
#echo off
:LOOP
cscript //nologo vbsEcho.vbs "\"
cscript //nologo vbsEcho.vbs "|"
cscript //nologo vbsEcho.vbs "/"
cscript //nologo vbsEcho.vbs "-"
goto :LOOP
EDIT: Using some of the ideas from aphoria's answer, this script will start the Windows calculator, and display a spinner until the calculator closes:
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET COUNT=1
START CALC
cscript //nologo vbsEcho.vbs "Calculating: \"
:LOOP
IF !COUNT! EQU 1 cscript //nologo vbsEcho.vbs "|"
IF !COUNT! EQU 2 cscript //nologo vbsEcho.vbs "/"
IF !COUNT! EQU 3 cscript //nologo vbsEcho.vbs "-"
IF !COUNT! EQU 4 (
cscript //nologo vbsEcho.vbs "\"
set COUNT=1
) else (
set /a COUNT+=1
)
pslist CALC >nul 2>&1
if %ERRORLEVEL% EQU 1 goto :end
goto :LOOP
:END
cscript //nologo vbsEcho.vbs ". Done."
paxdiablos has an amazing answer, but having to echo your commands into a payload file is annoying. It's hard to read and hard to debug. I took his code and modified it a bit for my own use:
#echo off
:: Localise environment.
setlocal enableextensions enabledelayedexpansion
set wkdir=%~dp0%
set wkdir=%wkdir:~0,-1%
set done_flag="%wkdir%\tmp_payload.flg"
set timeout=7
:controller
IF (%1)==() (
call :monitor step1 "Getting stuff from SourceSafe: "
call :monitor step2 "Compiling some PHP stuff: "
call :monitor step3 "Finishing up the rest: "
) ELSE ( goto %1 )
goto final
:step1
::ping for 5 seconds
ping 127.0.0.1 -n 6 >nul
del "%wkdir%\tmp_payload.flg"
goto final
:step2
::ping for 10 seconds
ping 127.0.0.1 -n 11 >nul
del "%wkdir%\tmp_payload.flg"
goto final
:step3
::ping for 5 seconds
ping 127.0.0.1 -n 6 >nul
del "%wkdir%\tmp_payload.flg"
goto final
:monitor
:: Create flag file and start the payload minimized.
:: echo the word "dummy" to the flag file (second parameter)
echo >>%done_flag% dummy
:: start the command defined in the first parameter
start /min cmd.exe /c "test2.bat %1"
:: Start monitoring.
:: i is the indicator (0=|,1=/,2=-,3=\).
:: m is the number of seconds left before timeout.
set i=0
set m=%timeout%
set str=%2
for /f "useback tokens=*" %%a in ('%str%') do set str=%%~a
<nul (set /p z=%str%^|)
:: Loop here awaiting completion.
:loop
:: Wait one second.
ping 127.0.0.1 -n 2 >nul
:: Update counters and output progress indicator.
set /a "i = i + 1"
set /a "m = m - 1"
if %i% equ 4 set i=0
if %i% equ 0 <nul (set /p z=^|)
if %i% equ 1 <nul (set /p z=/)
if %i% equ 2 <nul (set /p z=-)
if %i% equ 3 <nul (set /p z=\)
:: End conditions, complete or timeout.
if not exist %done_flag% (
::echo.
echo Complete
goto :final
)
if %m% leq 0 (
echo.
echo. *** ERROR: Timed-out waiting for child.
goto :final
)
goto :loop
:final
endlocal
You can use a counter that prints a different character from a given set (like "\|/-") and you change the character according to like "counter modulo 4". Anyway, you don't say in which language you're working in so it is a bit difficult to be more precise.
EDIT: now that we know in which environment you're playing in, I'd say that the BAT/CMD language is not really up to the task... I'd recommend any scripting language, Ruby being my favorite.
I find the easiest way is to update the title - that way you don't have to do a CLS all the time.
The reason for the two lines of ping -n, is that it's quicker for ping to do a double ping of a second each, versus a single ping of two seconds.
Also, for those who don't know, a :: is the same as a REM, except that the comments are ignored at the beginning of the parser (I think this is the right word) instead of at the end. Simply put, that line is ignored.
:: begin spin.cmd
#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
:: end spin.cmd
This routine examines the output of tasklist for a process you START from cmd.
Pass it the name of the exe as a parameter e.g.
call :spinner calc.exe
It reports
Elapsed: 001 seconds
and increments seconds until the exe process terminates.
The Elapsed 001 seconds message is overwritten each second by ECHO.exe -n \r
which echos a cr without a line feed.
Echo.exe is available at
http://www.paulsadowski.com/wsh/cmdprogs.htm
#echo off
start calc
call :spinner calc.exe
pause
:spinner
SET COUNT=1
:BEGIN
set "formattedValue=000000%count%"
ECHO.exe -n Elapsed: %formattedValue:~-3% seconds
ECHO.exe -n \r %= -n (suppress crlf) \r output a cr =%
SET /A COUNT+=1
set EXE=%1 %= search output of tasklist for EXE =%
set tl=tasklist /NH /FI "IMAGENAME eq %EXE%"
FOR /F %%x IN ('%tl%') DO IF %%x == %EXE% goto FOUND
set result=0
goto FIN
:FOUND
set result=1
:FIN
IF %result% EQU 0 GOTO END
PING -n 2 127.0.0.1 > nul %= wait for about 1 second =%
GOTO BEGIN
:END
start application, wait for loading
#echo off & setlocal enabledelayedexpansion
start application.exe
:1
for %%a in (^| ^/ ^- ^\ ^| ^/ ^- ^\) do (
for %%b in (^| ^/ ^- ^\ ^| ^/ ^- ^\) do (
for %%c in (^| ^/ ^- ^\ ^| ^/ ^- ^\) do (
cls &echo processing..%%c%%b%%a
sleep -m 20
IF EXIST "result file" (exit)
)))
goto 1
:LOOP
ECHOX -n "~r%Processing..."
IF %CTR% EQU 4 SET /A CTR=0
IF %CTR%==0 (set /p DOT=³)<NUL
IF %CTR%==1 (set /p DOT=/)<NUL
IF %CTR%==2 (set /p DOT=Ä)<NUL
IF %CTR%==3 (set /p DOT=\)<NUL
ECHOX -n "~r"
SET /A CTR+=1
SET /A TCT+=1
IF %TCT% GTR %MAX_COUNT% GOTO :END
GOTO :LOOP

Resources