Combination of `sleep` and `pause` command - batch-file

Ok, after seeing crazy stuff being completed in so little code, I have high hopes this is possible.
Pretty much, I want to use the pause command normally, however, if the user doesn't input anything for a specified duration of time, it automatically continues.
In pseudo code:
(sleep %sleep-time%&Echo Pass)1>0 & pause
I thought at first I could do this using start /b to create a process that echoed input while being paused i the current thread, but that could cause problems if the user does input something.
Bonus
What would be really cool is if the errorlevel would be changed based on whether the user inputted something, or if the pause command timed out.

I suggest using timeout:
timeout /T 60 >NUL
This will sleep your script for 1 minute, or unless the user hits a key.

#echo off
setlocal
rem TimedPause.bat - Antonio Perez Ayala
if "%1" equ ":PausePart" goto PausePart
if "%1" neq "" goto begin
echo TimedPause.bat seconds
echo/
echo Wait for given seconds or until user press a key
echo At end, the presence of keyPressed.txt file indicate the cause of exit
goto :EOF
:begin
set seconds=%1
start "" /B "%~F0" :PausePart
for /F "skip=2 tokens=2 delims=," %%a in ('tasklist /FI "IMAGENAME eq cmd.exe" /FO CSV') do (
set PausePart=%%a
goto TimePart
)
:TimePart
ping -n 2 localhost > NUL
if exist keyPressed.txt goto :EOF
set /A seconds-=1
if %seconds% gtr 0 goto TimePart
taskkill /PID %PausePart% /F > NUL
goto :EOF
:PausePart
del keyPressed.txt 2> NUL
pause
echo %time% > keyPressed.txt
exit

Related

Loop a batch file only 5 times

Ive been trying to loop a batch file exactly 5 times using the set /a operation and so far no luck! Could someone help me?
#ECHO OFF
set loopCount=0
:loop
echo Checked %loopCount% times...
set /a loopCount=1+%loopCount%
if loopCount == 5 (goto exit) else (goto loop)
:exit
cls
echo Finished after %loopCount% times
pause >nul
Best of luck to whoever can help me
Here's a couple of examples to help you.
Using GoTo with a label:
#Set "loopCount=0"
:loop
#Set /A loopCount += 1
#Rem Some actual command goes here.
#Echo Checked %loopCount% times...
#If %loopCount% Lss 5 GoTo loop
#%SystemRoot%\System32\timeout.exe /T 2 /NoBreak 1>NUL
#ClS
#Echo Finished after being checked %loopCount% times.
#Pause 1>NUL
Alternatively, using a For /L looping mechanism:
#Set "maxCount=5"
#For /L %%G In (1,1,%maxCount%) Do #(
Rem Some actual command goes here.
Echo Checked %%G times...
)
#%SystemRoot%\System32\timeout.exe /T 2 /NoBreak 1>NUL
#ClS
#Echo Finished after being checked %maxCount% times.
#Pause 1>NUL
If you need to execute the entire batch script 5 times, the following method of storing an execution count in an alternate data stream of the script can be used:
#Echo off
more < "%~f0:Count" 2>&1 > nul && (
For /f "usebackq delims=" %%G in (`more ^< "%~f0:Count"`)Do Set /A Count=%%G+1
) || (
Set /A "Count+=1"
)
Echo(%Count% >"%~f0:Count"
:# Your script below
Echo(Script execution: %Count%
:# Terminate script execution after count reached
If %Count% EQU 5 (
Echo(0 >"%~f0:Count"
Exit /B
)
"%~f0"

Batch File auto quits. I can't find the error

I have been coding a small thing that, rather stupidly, has been taking me a while. What it is meant to do is always have a certain excel spreadsheet (named Homework.xlsx) open between two certain times (4:30 and 5:30). The thing is it doesn't actually stay open to check for those times, even though I have it set to a loop that repeats every minute.
Here is the code:
SET "stime=16:30:00.00"
SET "etime=17:30:00.00"
:start
TASKLIST /FI "IMAGENAME EQ EXCEL.EXE" 2>NUL | FIND /I /N "EXCEL.EXE" >NUL
IF %ERRORLEVEL% = 0 (
SET Erunning=true
) ELSE (
SET Erunning=false
)
IF EXIST C:\Users\Hunter\Documents\HOMEWORKSHEETISOPEN.txt (
IF %Erunning%=false (
DEL C:\Users\Hunter\Documents\HOMEWORKSHEETISOPEN.txt
)
)
IF EXIST C:\Users\Hunter\Documents\HOMEWORKSHEETISOPEN.txt (
SET running=true
) ELSE (
SET running=false
)
FOR /F %%F IN ('wmic path win32_localtime get dayofweek^|Findstr [0-6]') DO SET DOW=%%F
IF %time% GEQ %stime% IF %time% LEQ %etime% IF %running%==false IF %DOW% NEQ 6 IF %DOW% NEQ 0 (
START /MAX C:\Users\Hunter\OneDrive\Homework.xlsx
ECHO IMRUNNING > C:\Users\Hunter\Documents\HOMEWORKSHEETISOPEN.txt
)
TIMEOUT 60 /NOBREAK > NUL
GOTO start
Your code is not just convoluted, but also inefficient. If the purpose is open an excel spreadsheet in Monday..Friday # %stime%...%etime% range, then there are simpler ways to do that. For example:
SET "stime=16:30:00.00"
SET "etime=17:30:00.00"
:start
rem Check the day
FOR /F %%F IN ('wmic path win32_localtime get dayofweek^|Findstr [0-6]') DO SET DOW=%%F
IF %DOW% EQU 0 GOTO wait1hour
IF %DOW% EQU 6 GOTO wait1hour
rem Check the time
IF %time% LSS %stime% GOTO wait1min
IF %time% GTR %etime% GOTO wait1min
rem Open the spreadsheet and wait until it is closed
START /MAX C:\Users\Hunter\OneDrive\Homework.xlsx | PAUSE > NUL
GOTO start
:wait1min
TIMEOUT 60 /NOBREAK > NUL
GOTO start
:wait1hour
TIMEOUT 3600 /NOBREAK > NUL
GOTO start
You may also calculate the exact number of seconds to wait if the %time% check fail, so the wait method be more efficient; I suggest you to use this method for such a calculation. You may also start the program in Mon..Fri range at the desired hour using the Windows Task Scheduler.

Set /p Instantly

I've been trying to create a file that times the user's input.
I could get this file
start /min b1.bat
(:b1.bat)
#echo off
cls
set num=0
:time
set /a num=%num%+1
echo %num% >waiter.txt
set time=0
:wait
cls
set /a time=%time%+1
if "%time%" equ "1000" goto time
goto wait
Here, b1.bat counts the secconds passed since it has started.
(:b2.bat)
cls
:begin
set /p time= <waiter.txt
echo %time%
if "%time%" equ "5" echo Five secconds.
set /p cho=Input:
goto begin
I would like to know how to make b2.bat do something if no input was given for an amount of time. No input at all, not even a press of enter.
So, if I didn't press any key at all and a minute has passed, it prints A minute has passed without input.
I hope this makes sense to you.
Before I answer your question, I need to point out that looping 1000 times does not necessarily mean you've paused for 1 second. There are better ways to sleep -- timeout /t seconds in Vista or newer, or ping -n seconds+1 localhost or choice /t seconds in XP. You should also avoid stomping on existing environment variables, such as %time%.
To answer your question, there's no graceful way to set a timeout for set /p. You can, however, launch a background thread within the same window using start /b to echo things on an interval. You can set up inter-thread communication between the active thread and the background using waitfor (Vista or newer only) to reset the timer, and set the helper thread to self-destruct when waiter.txt disappears.
And as long as you're launching one helper thread within the same window, might as well put your waiter.txt thread there as well. Why spawn a minimized window when you can reuse the one you already have? And since we're merging process threads within the same window, might as well go one step further and merge all your scripts into one script that re-launches itself with different arguments for different threads.
#echo off
setlocal
if "%~1"=="" (
>waiter.txt echo 0
start /b "" "%~f0" helper1
start /b "" "%~f0" helper2
) else goto %~1
:begin
cls
set /p "seconds="<waiter.txt
echo Alive for %seconds%s.
:read-host
set "cho="
set /p "cho="
if not defined cho goto read-host
rem // delayed expansion prevents evaluation of special characters in user input
setlocal enabledelayedexpansion
for %%c in (quit exit die EOL) do if /i "!cho!"=="%%c" (
del waiter.txt
echo OK, bye!
)
rem // send signal to helper2 acknowledging entry
waitfor /s %computername% /si UserEntry >NUL 2>NUL
if not exist waiter.txt exit /b
rem // ========================================
rem // Do something meaningful with !cho! here.
rem // ========================================
endlocal
goto begin
rem // formerly b1.bat
:helper1
set "num=0"
:helper1_loop
timeout /t 1 /nobreak >NUL 2>NUL
set /a num+=1
if not exist waiter.txt exit
>waiter.txt echo %num%
goto helper1_loop
:helper2
if not exist waiter.txt exit
waitfor /t 60 UserEntry >NUL 2>NUL || (
echo A minute has passed without input.
)
goto helper2
For extra credit, let's get rid of waiter.txt as well. I'm not sure whether this paranoia is founded or not, but I believe that hard drive sectors can endure a finite number of writes. Rewriting waiter.txt once a second for potentially hours bothers me. So let's create a hybrid Jscript chunk to calculate the seconds elapsed between the start of the script and now.
To control execution of the background helper thread, we'll still use a temporary file, but we'll use a lock file that will only be written once, then deleted at the end.
#if (#CodeSection == #Batch) #then
#echo off
setlocal
if "%~1"=="" (
rem // relaunch self as helper if lock file is writeable
2>NUL (>"%~dpn0.lock" type NUL) && start /b "" "%~f0" helper
rem // create a lock file for the duration of the main runtime
rem // Credit: Dave Benham -- https://stackoverflow.com/a/27756667/1683264
8>&2 2>NUL (2>&8 9>"%~dpn0.lock" call :init) || (
echo Only one instance is allowed.
timeout /t 3 /nobreak >NUL
exit /b
)
) else goto %~1
rem // cleanup and end main runtime
del "%~dpn0.lock" >NUL 2>NUL
waitfor /s %computername% /si UserEntry >NUL 2>NUL
exit /b
:init
rem // set %start% to current epoch
call :jscript start
:begin
cls
call :jscript seconds
echo Alive for %seconds%s.
:read-host
set "cho="
set /p "cho="
if not defined cho goto read-host
rem // delayed expansion prevents evaluation of special characters in user input
setlocal enabledelayedexpansion
for %%c in (quit exit die EOL) do if /i "!cho!"=="%%c" (
echo OK, bye!
exit /b
)
rem // send signal to helper2 acknowledging entry
waitfor /s %computername% /si UserEntry >NUL 2>NUL
rem // ========================================
rem // Do something meaningful with !cho! here.
rem // ========================================
endlocal
goto begin
:helper
del "%~dpn0.lock" >NUL 2>NUL
if not exist "%~dpn0.lock" exit
waitfor /t 60 UserEntry >NUL 2>NUL || (
echo A minute has passed without input.
)
goto helper
:jscript
for /f %%I in ('cscript /nologo /e:JScript "%~f0" "%start%"') do set "%~1=%%I"
goto :EOF
#end // end batch / begin JScript hybrid code
WSH.Echo(
WSH.Arguments(0)
? Math.round((new Date() - WSH.Arguments(0)) / 1000)
: new Date().getTime()
);

batch file to check if exe is running if so taskkill

I'm having problems with the firefox Flashplayerplugin eating up too much ram and lagging my system when it's not in use. The only solution I found was killing the flashplayerplugin while using firefox, uninstalling, reinstalling or a fresh firefox install or new profile doesn't solve it; however, it's becoming very tedious having to check taskmanager all the time and kill it and the flashplayerplugin always seems to start on it's own.
The question I have is if it's possible to create a batch file to check if FlashPlugin_11_8_800_94.exe is running and kill it after a period of time (5-10 seconds) and continue running the batch file actively, in a loop, scanning if FlashPlugin_11_8_800_94.exe has started again, then kill it after 5 - 10 seconds, rinse and repeat?
Edit:
Found a batch file and modified it, but also seems to be missing some perimeters to actively search if it's running, even when it is not. It doesn't work either way though.
#echo off
:search
TASKLIST|FIND "FlashPlayerPlugin"
IF %ERRORLEVEL% = 0 THEN (GOTO found)
TIMEOUT /T 5
GOTO search
:found
taskkill /im FlashPlayerPlugin_11_8_800_94.exe
--
This batch file doesn't work either.
set tasklist=%windir%\System32\tasklist.exe
set taskkill=%windir%\System32\taskkill.exe
-------------------------------------------------------
:STOPPROC
set wasStopped=0
set procFound=0
set notFound_result=ERROR:
set procName=%1
for /f "usebackq" %%A in (`%taskkill% /IM %procName%`) do (
if NOT %%A==%notFound_result% (set procFound=1)
)
if %procFound%==0 (
echo The process was not running.
goto :EOF
)
set wasStopped=1
set ignore_result=INFO:
:CHECKDEAD
"%windir%\system32\timeout.exe" 3 /NOBREAK
for /f "usebackq" %%A in (`%tasklist% /nh /fi "imagename eq %procName%"`) do (
if not %%A==%ignore_result% (goto :CHECKDEAD)
)
goto :EOF
-------------------------------------------------------
:MAIN
call :STOPPROC FlashPlayerPlugin_11_8_800_94.exe
taskkill /im FlashPlugin_11_8_800_94* /f >nul 2>&1
For anyone who still might find it useful:
This is a small script that scans tasklist for processes containing processname once every 5 seconds. For example, if you put "notepad" for the processname, it will end processes like "notepad.exe" and "notepad++.exe". To use the script, copy and paste the following into notepad and save has "simple_pk.cmd". processname can have any characters except double quotes("), ampersands (&), or commas (,).
::Simple monitor and kill process
#echo off&prompt :&mode con cols=50 lines=10
set processname=flashplayerplugin
:loop
cls&echo Searching for %processname%...
for /f "tokens=1 delims=," %%a in ('tasklist /fo csv ^|FINDSTR /I /C:"%processname%"') do call :killprocess %%a
ping -n 6 127.0.0.1>NUL
goto :loop
:killprocess
echo. |set /p d=killing %*...
taskkill /f /im "%*">nul 2>&1
set err=%errorlevel%
set success=Success
if not %err%==0 set success=fail (err code: %err%)
if %err%==128 set success=fail (process not found)
echo %success%&goto :eof
This is a slightly different version of the same script. This will only end processes that match the whole name exactly:
::Simple monitor and kill process (exact name)
#echo off&prompt :&mode con cols=50 lines=10
set processname=FlashPlayerPlugin_11_8_800_94.exe
:loop
cls&echo Searching for %processname%...
for /f "tokens=1 delims=," %%a in ('tasklist /fo csv ^|FINDSTR /C:"%processname%"') do call :killprocess %%a
ping -n 6 127.0.0.1>NUL
goto :loop
:killprocess
set name=%*
set name=.,;%name:"=%;,.
echo %name%|FINDSTR /C:".,;%processname%;,.">nul || goto :eof
echo. |set /p d=killing %*...
taskkill /f /im "%*">nul 2>&1
set err=%errorlevel%
set success=Success
if not %err%==0 set success=fail (err code: %err%)
if %err%==128 set success=fail (process not found)
echo %success%&goto :eof
Your IF is not correct:
#echo off
:search
TASKLIST|FIND "setup.exe"
IF %ERRORLEVEL% equ 0 (GOTO found)
TIMEOUT /T 5
GOTO search
:found
taskkill /im setup.exe
More simpler form
#echo off
:search
TASKLIST|FIND "setup.exe"
IF %ERRORLEVEL% equ 0 (taskkill /im setup.exe
exit)
TIMEOUT /T 5
GOTO search
I was looking over the first bit of code at top and I find a way, I believe. This is what I got; really simple.
#echo off
cls
:start
timeout /t 5
tasklist|find "explorer.exe"
goto found
goto start
:found
taskkill /f /im explorer.exe
goto start
Of course, any program will work.

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