How to use the timeout command in batch language? - windows

I actually wanted to create a timer using batch program and when I run the code the output is not the way I want. The screen continues flicking without decreasing the second. Can someone Help me. Thanks alot.
#echo off
set countdown=10
:loop
if %countdown% == 0 goto end
cls
echo %countdown%
timeout /t 1 /NOBREAK
set/a count=%countdown%-1
goto loop
:end
cls
echo Time's up!
pause

You should replace this line set/a count=%countdown%-1 by this one set /a countdown=countdown-1 or by a shortened set /a countdown-=1.
#echo off
set "countdown=10"
:loop
if "%countdown%" EQU "0" goto end
cls
echo %countdown%
set /a countdown-=1
timeout /t 1 /NOBREAK>nul
goto loop
:end
cls
echo Time's up!
pause

A way to do it without the goto / label
#echo off
Set count=10
Setlocal enableDelayedExpansion
For /L %%a in (1,1,!count!) DO (
Set /a count=!count! - 1
(ECHO <esc>[1;1H<esc>[K!count!)
(
TIMEOUT 1 >nul
)
)
ECHO times up!
pause
<esc>[1;1H<esc>[K Sets the position of the text (line;column) and clears the line from that point. <esc> represents the ANSI escape character.
Using the ANSI cursor positioning allows you to refresh text on screen selectively, without having to clear the whole screen.

Related

Windows Command Prompt print text file with delay

I have no experience with command prompt whatsoever, but I'd like to make a batch script (for fun and learn) that would print a text file from a given location, line by line, with a 1 second delay.
I would also want it to be able to pause/unpause when I press a designated key (ex: space) and feed me an extra line (on top of those already programmed to run) when I press another key (ex: enter).
I know I can add a 1 second delay by pinging localhost ping -n 5 127.0.0.1 > nul
And I know I can see the content of a text file using more text.txt, but I don't know how to iterate through an entire text file until EOF is met and I don't know how to pause/resume and feed extra line.
Hope it doesn't sound stupid or out of scope in this context, but it's just something that interests me right know and I know a lot people here have the knowledge to do this.
1) If you have experience in programming, you will know using a for loop is the most common way to do things one by one, e.g. line by line.
2) You can simply use ping localhost -n 2 >nul for 1 second delay, the 2 in the ping is not indicating 2 seconds, but 1 second instead. (I have no idea about that, just get used to it)
3) You can't pause/unpause when cmd is pinging, I mean there's no way to force the program to pause/unpause because the delay process is executed in just a line of code! Or you can magically add some code into it like ping localhost -n 2 pause while(KeyDown(SPACE)) >nul (just kidding :) )
4) Extra lines? Hmm... Remember batch is not a powerful language so... Yeah
Here is a simple code to print text line by line each second in a .txt file
for /f %%a in (your_text.txt) do (
echo %%a
ping localhost -n 2 >nul
)
You could do it synchronously with choice /t 1 (for a 1-second timeout) and some key other than Spacebar. Perhaps P for Pause?
#echo off
setlocal
set "textfile=notes.txt"
echo Hit P to pause / resume, Q to quit.
echo;
for /f "tokens=1* delims=:" %%I in ('findstr /n "^" "%textfile%"') do (
echo(%%J
choice /t 1 /c €pq /d € >NUL
if errorlevel 3 exit /b 0
if errorlevel 2 (
pause >NUL
ping -n 1 -w 750 169.254.1.1 >NUL
)
)
exit /b 0
Unfortunately, choice only allows a-z, A-Z, 0-9, and extended characters 128-254. There's no way to make it listen for Enter or Space. And choice is the only Windows command of which I'm aware that'll accept a single keypress and do something meaningful based on which key was pressed.
I think you'll have to use some sort of compiled language (or possibly PowerShell with a .NET class?) to listen for keypress events on the console. You could probably do it in JavaScript, but you'd have to display your output in a web browser or HTA window.
A "scrolling editor"? It is a crazy idea, isn't it? I LIKE IT! ;-) I adopted your project and add some points...
#echo off
rem ScrollEditor.bat: "dynamic" very simple line editor
rem Antonio Perez Ayala aka Aacini
if "%~1" neq "" if "%~1" neq "/?" goto begin
echo ScrollEditor.bat filename.ext
echo/
echo File lines will be continually scrolling, one per second.
echo/
echo You may pause the scroll via P key. In the "paused" state, the last displayed
echo line is named "current line", and the following commands are active:
echo/
echo #L Return/advance the listing to line #; continue the scroll from there.
echo [#]D Delete [from previous line # up to] current line.
echo I Insert lines after current line; end insert with *two* empty lines.
echo P End "paused" state; continue the scroll from current line on.
echo E End edit and save file, keep original file with .bak extension.
echo Q Quit edit, not save file.
goto :EOF
:begin
if not exist %1 echo File not found & goto :EOF
rem Load file lines into "line" array
set /P "=Loading file... " < NUL
setlocal DisableDelayedExpansion
for /F "tokens=1* delims=:" %%a in ('findstr /N "^" %1') do (
set "line[%%a]=%%b"
set "lastLine=%%a"
)
echo last line: %lastLine%
echo To pause scrolling, press: P
echo/
setlocal EnableDelayedExpansion
set "validCommands=LDIPEQ"
set currentLine=1
:command-P End "paused" state
:ScrollLine
if %currentLine% gtr %lastLine% (
set "currentLine=%lastLine%"
echo EOF
goto GetCommand
)
set "num= %currentLine%"
echo %num:~-4%: !line[%currentLine%]!
set /A currentLine+=1
choice /C PC /N /T 1 /D C >NUL
if errorlevel 2 goto ScrollLine
rem Enter paused state
set /A currentLine-=1
:GetCommand
echo/
set /P "command=Command [#L,#D,I,P,E,Q]? "
set "letter=%command:~-1%"
if "!validCommands:%letter%=!" equ "%validCommands%" goto GetCommand
goto command-%letter%
:command-L Go to line #; continue scrolling
set "currentLine=%command:~0,-1%"
goto ScrollLine
:command-D Delete from line # to current line
set "prevLine=%command:~0,-1%"
if not defined prevLine set "prevLine=%currentLine%"
rem Move lines after last deleted one into deleted lines
set /A currentLine+=1, newCurrent=prevLine-1, lines=currentLine-prevLine
for /L %%j in (%currentLine%,1,%lastLine%) do (
set "line[!prevLine!]=!line[%%j]!"
set /A prevLine+=1
)
set /A currentLine=newCurrent, lastLine=prevLine-1
if %currentLine% equ 0 set "currentLine=1"
echo %lines% line(s) deleted (current=%currentLine%, last=%lastLine%)
goto GetCommand
:command-I Insert lines after current one
echo End insert with *two* empty lines
echo/
rem Read new lines into "ins" array
set "newLine=%currentLine%"
:insertLine
set "line="
set /A newLine+=1
set "num= %newLine%"
set /P "line=+%num:~-3%: "
set "ins[%newLine%]=!line!"
rem The most complex part: end in two empty lines...
if not defined line (
set /A newLine+=1
set "num= !newLine!"
set /P "line=+!num:~-3!: "
if defined line (
set "ins[!newLine!]=!line!"
) else (
set /A newLine-=2
)
)
if defined line goto insertLine
rem Move old lines to new place to make room for new lines
set /A lines=newLine-currentLine, currentLine+=1, newLast=lastLine+lines
for /L %%j in (%lastLine%,-1,%currentLine%) do (
set "line[!newLast!]=!line[%%j]!"
set /A newLast-=1
)
rem Insert new lines in old place
for /L %%j in (%currentLine%,1,%newLine%) do set "line[%%j]=!ins[%%j]!"
set /A lastLine+=lines, currentLine=newLine
echo %lines% line(s) inserted (current=%currentLine%, last=%lastLine%)
goto GetCommand
:command-E End edit, save file
echo Saving file...
move /Y %1 "%~N1.bak"
(for /L %%i in (1,1,%lastLine%) do echo(!line[%%i]!) > %1
:command-Q Quit edit
echo End edit
This program have multiple problems: don't check for valid input in commands, may have problems with special Batch characters and if the first character of a line is a colon, eliminate it. However, it is a good starting point for this project!
Perhaps you may be interested in this similar project.

Windows batch file looping Wait animation during processing command

I have created the following batch file that makes Wait "| / -- \" animation. I want to use it during processing mysql restore database command mysql -u %DBuser% -p %DB% < "%thefile%" where thefile is the sql dump file path
#Echo OFF
setlocal EnableDelayedExpansion
for /f %%a in ('copy /Z "%~f0" nul') do set "CR=%%a"
SET p=-1
set num=1
set "st[1]=| "
set "st[2]=/ "
set "st[3]=--"
set "st[4]=\ "
if /i %p% lss 0 (
set p=2
call :LOOP
call :DoSomeThing
)
:LOOP
if /i %num% lss 4 (
set /a num=num+1
) else (
set num=1
)
<nul set /P "=Wait !st[%num%]!!CR!"
TIMEOUT /T 1 >NUL
GOTO :LOOP
:DoSomeThing
TIMEOUT /T 10 >NUL
echo Doing...
Here, :DoSomeThing is for testing purposes and It should be replaced or include the mysql command. I get the problem that :LOOP works for ever and there is no call to :DoSomeThing
I tried to call :DoSomeThing before call :LOOP but the LOOP started after DoSomeThing is finished so it becomes useless! Is there any way to make the DoSomeThing or the MySQL command works in the background while the animation wait loop works too?
EDIT: Some explanations added
In order to fulfill your request it is necessary to execute two threads simultanously, so one thread execute the mysql command and the other thread execute the looping wait animation. Both threads can be synchronized using a flag file that is created before mysql execution starts and is deleted after it ends, so the wait animation loops until the flag file is deleted.
The way to create a new thread is via start command, that may run a second Batch file that execute the mysql command and delete the flag file. However, in order to keep all the code in the same place, the start command may run the same Batch file (represented by "%~F0" in the code below). The key that allows this trick to work is a special parameter that indicate if the Batch file was re-executed from inside itself, so in this case the code just goto the section that execute the mysql command and delete the flag file.
#Echo OFF
rem If the Batch file was re-executed with the special parameter (second thread)
rem go to the section that execute the mysql command
if "%~1" equ ":DoSomething" goto %1
setlocal EnableDelayedExpansion
for /f %%a in ('copy /Z "%~f0" nul') do set "CR=%%a"
set num=0
set "st[0]=| "
set "st[1]=/ "
set "st[2]=--"
set "st[3]=\ "
rem Do here anything you want before the mysql command...
echo Doing something for 10 seconds...
rem Create the flag file
echo X > DoingSomething
rem Re-start this Batch file with the special parameter
start "" /B "%~F0" :DoSomething
rem Simultaneously execute the waiting animation
call :LOOP
rem Do here anything you want after the mysql command...
rem ... and terminate
goto :EOF
:LOOP
set /a num=(num+1) %% 4
<nul set /P "=Wait !st[%num%]!!CR!"
TIMEOUT /T 1 >NUL
IF EXIST DoingSomething GOTO :LOOP
echo Ending loop
goto :EOF
:DoSomeThing
rem Place here the mysql command
TIMEOUT /T 10 >NUL
rem Delete the flag file
del DoingSomething
rem And terminate the second thread
goto :EOF

Windows batch file script IF does not work

I have tried to make Windows batch file that blinking the word "Wait" & "Wait..". I tried the following code:
#Echo OFF
setlocal EnableDelayedExpansion
for /f %%a in ('copy /Z "%~f0" nul') do set "CR=%%a"
SET p=-1
set num=2
set st[1]=Wait
set st[2]=Wait..
set st[3]=eer
:LOOP
if /i %num% equ 1 (
set num=2
) else (
set num=1
)
<nul set /P "=!st[%num%]!!CR!"
TIMEOUT /T 1 >NUL
GOTO :LOOP
The problem here, the IF seems to be worked only one time. i.e running the batch makes it prompt "Wait" only one time, then "Wait.." forever. What is the mistake here?
You problem is not the if (that works as intended), your problem are the spaces that should delete/overwrite the dots.
set "st[1]=Wait "
set "st[2]=Wait.."

Implementing timed input in batch file. (countdown to a minute)

I am using windows 8 to write a batch file and I got stuck in implementing the timer in batch file. I want to ask input from the user and give them one minute to type their input. Once the time hit a minute then display message like 'the time is over'. So, the time will start from 1 second and ends at 60 seconds OR start from 60 seconds and going down to 0 second. Either works just fine.
Additionally, I want timer to be displayed somewhere on screen so that they can see the countdown. Also, while the timer is running I want the user to be able to type a word and hit enter. This program will not make user wait, but it will wait until the time is over OR as soon as the user enter a word (whichever comes first). After they enter a valid word then I want to store that word in certain variable and do something like (goto VALIDWORD OR echo That is a valid word!)
I don't know if this is possible in batch file and there are more advanced language to use, but I want to complete this program using batch scripting. Thank you.
Following is my concept:
#echo off
:Start
color EC
set /a time =60
:loop
cls
if %time% EQU 0 goto Timesup
if %time% LEQ 60 goto CONTINUE
:CONTINUE
ping localhost -n 2 >nul
set /a time-=1
set /p cho= Enter your word:
echo Remaing Time: %time%
goto loop
:Timesup
echo The time is over!
exit
Any ideas or support would be appreciated. Again Thanks!
Batch files are not designed for tasks like this one, but it is possible to perform certain advanced managements although in a limited manner. The subroutine below use choice command to get input keys, so it does not allow to end the input with Enter key nor to delete characters with BackSpace; it use 0 and 1 keys for such tasks.
#echo off
setlocal
call :ReadTimedInput 60 word=
echo Word read: "%word%"
goto :EOF
:ReadTimedInput seconds result=
setlocal EnableDelayedExpansion
set /A seconds=100+%1
set "letters=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
for /F %%a in ('copy /Z "%~F0" NUL') do set "CR=%%a"
for /F %%a in ('echo prompt $H ^| cmd') do set "BS=%%a"
echo Enter a word; press 0 to End, press 1 to Clear
:clear
set /P "=X!CR! !CR!" < NUL
set "result="
:loop
set /P "=X!BS! !CR!%seconds:~-2%: %result%" < NUL
choice /C ¡10%letters% /N /CS /T 1 /D ¡ > NUL
if %errorlevel% equ 1 goto tick
if %errorlevel% equ 2 goto clear
if %errorlevel% equ 3 echo/& goto endInput
set /A char=%errorlevel%-4
set "result=%result%!letters:~%char%,1!"
:tick
set /A seconds-=1
if %seconds% gtr 100 goto loop
echo !CR!00
set "result=Time out"
:endInput
endlocal & set "%2=%result%"
exit /B

How can I copy a statically named file to another location with increasing numerical suffixes?

I've got three files in a directory that appear via another process:
c:\result\results-a.txt
c:\result\results-b.txt
c:\result\results-c.txt
Each time they all appear, I'd like to copy them to another directory with an increasing numerical suffix/prefix, once the files are copied they can be deleted. Every time the batch file starts, it can start with the number 0 (it doesn't have to scan the target directory and continue).
Ex. The first time the files all appear, the target directory might look like this:
c:\archive\results-a.0000.txt
c:\archive\results-b.0000.txt
c:\archive\results-c.0000.txt
The second time they appear, the target directory would then contain:
c:\archive\results-a.0000.txt
c:\archive\results-b.0000.txt
c:\archive\results-c.0000.txt
c:\archive\results-a.0001.txt
c:\archive\results-b.0001.txt
c:\archive\results-c.0001.txt
And so on. I'm comfortable piecing this together in a BASH enviroment, but my client requires this be done on a Windows NT (Windows 7, actually) machine. Could someone get me started?
[Edit - Answer]
Thanks to Joey below, this is what I ended up coding.
#echo off
setlocal enabledelayedexpansion
set Counter=0
:loop
call :test_file %1\results1.txt
call :test_file %1\results2.txt
call :test_file %1\results3.txt
timeout 2 /nobreak >nul
call :movefiles
timeout 2 /nobreak >nul
goto loop
:test_file
timeout 2 /nobreak >nul
if not exist %1 goto :test_file
goto :eof
:lz
set LZ=000%Counter%
set LZ=%LZ:~-4%
goto :eof
:movefiles
for %%f in (C:\test\*.txt) do (
call :lz
move "%%f" "c:\tmp\c-!LZ!-%%~nxf"
)
set /a Counter+=1
goto :eof
A very nice introduction to batch programming. Thanks.
You need a few pieces for this to work.
First of all, a counter:
set Counter=0
Then a subroutine that pads the value with leading zeroes:
:lz
set LZ=000%Counter%
set LZ=%LZ:~-4%
goto :eof
The %LZ:~-4% is a substring operation that retains the last four characters of the variable value. In this case this is a number, zero-padded to four places.
A loop that checks for files in a certain location:
:loop
if exist c:\result\*.txt call :movefiles
timeout 2 /nobreak >nul
goto loop
Fairly readable, this one, I guess.
A subroutine that moves the files away:
:movefiles
setlocal enabledelayedexpansion
for %%f in (C:\result\*.txt) do (
rem Generate the zero-padded number
call :lz
move "%%f" "some\target\directory\%%~nf.!LZ!%%~xf"
)
endlocal
rem Increment the counter for next use
set /a Counter+=1
goto :eof
Piecing all that together leaves you with
#echo off
setlocal enabledelayedexpansion
set Counter=0
:loop
if exist c:\result\*.txt call :movefiles
timeout 2 /nobreak >nul
goto loop
:lz
set LZ=000%Counter%
set LZ=%LZ:~-4%
goto :eof
:movefiles
for %%f in (C:\result\*.txt) do (
call :lz
move "%%f" "some\target\directory\%%~nf.!LZ!%%~xf"
)
set /a Counter+=1
goto :eof
It can be adapted to remember its last value. However, this will only work if the batch file resides in a writable location.
#echo off
setlocal enabledelayedexpansion
set Counter=0
call :init
:loop
if exist c:\result\*.txt call :movefiles
timeout 2 /nobreak >nul
goto loop
:lz
set LZ=000%Counter%
set LZ=%LZ:~-4%
goto :eof
:movefiles
for %%f in (C:\result\*.txt) do (
call :lz
move "%%f" "some\target\directory\%%~nf.!LZ!%%~xf"
)
set /a Counter+=1
>>%~dpnx0 echo set Counter=%Counter%
goto :eof
:init
Note that the last line (:init) must be terminated with a line break (or better two; I had some issues sometimes with just one in my testing here). This essentially creates a subroutine at the end of the batch file that sets the counter repeatedly until it arrives at its last value.
It isn't exactly fast, though. There will be one set call per counter increment at the end, and all those will be run initially.
Here's something that should get you started. Drop this in a file called incrementName.bat and then run it several times in succession.
#echo off
goto :start
--------------------------------------------
incrementName.bat
shows how to generate a filename with a monotonically
increasing numeric portion.
Run this several times in succession to see it in action.
Mon, 18 Apr 2011 12:51
--------------------------------------------
:START
setlocal enabledelayedexpansion
call :GETNEXTFILENAME rammalamma.txt
echo Next: %nextname%
#REM copy self to that new name.
copy %0 %nextname%
GOTO END
--------------------------------------------
:GETNEXTFILENAME
#REM this is a subroutine.
#REM %1 is the basename. This logic assumes a 3-character
#REM filename extension.
set fname=%1
set ext=%fname:~-3%
set base=%fname:~0,-4%
set idx=0
:toploop1
#set NUM=00000!idx!
set nextname=%base%.!NUM:~-5!.%ext%
if EXIST !nextname! (
if !idx! GTR 99999 goto:FAIL
set /a idx=!idx! + 1
goto:toploop1
)
)
:Success
goto:EOF
:Fail - overflow
set nextname=%base%.xxxxx.%ext%
goto:EOF
--------------------------------------------
:END
endlocal

Resources