I think someone asked a similar questions ,but mine is a bit different. I have this code:
#echo off
title Game
set time=1 am
timeout 10 /nobreak >nul & goto game
set time=2 am
:game
How can I make the
timeout 5 /nobreak >nul
and
goto game
work at the same time? This is how I want it to work if you still didn't get it:
The timeout starts and you play the game after the timeout ends it changes the time to 2 am. How can I do that at the same time and play the game without getting disturbed? Please help. Thanks!
No, Bob. 'tis you who doesn't get the point about the variable time. It is a reserved variable which is set by the system, but can be overridden by a user script. Virtually any other variable name, you can use - just not time, date, path, random and a few others.
As to your problem,
set "mytime=1 am"
call :starttimer
:game
... whatever
:getinput
set "response="
set /p "response=%~1"
if not exist timerfinished.txt goto :eof
:: here change "mytime"
set "mytime=2 am"
:starttimer
start /min "" timer.bat 10
goto :eof
where timer.bat is
#echo off
del timerfinished.txt 2>nul
timeout %1 /nobreak>nul
echo.>timerfinished.txt
exit
The timer.bat file simply deletes the flag-file timerfinished.txt, delays for the time set by the first parameter it receives (%1 - set to 10 in main code) then creates the file and exits.
The main code starts the timer initially using :starttimer then whenever you want to prompt-and-wait-for-a-response, you execute
call :getinput "Prompt for input "
and the response will appear in %response%.
Note that setting response to nothing initially in this routine ensures that the response is empty if the user simply presses Enter
OK - so nothing actually happens using this scheme until you enter a response, only then will the time be incremented and the game continues with an updated time. If you're expecting that the end of the timeout actually does something, really - that's not going to happen - unless you use choice to input your responses with the timeout option.
i think you are looking for a "game time", running faster than real time.
Best way: use another script to set a gametime variable (like below) in a separate (minimized) window. Whenever you need to access the current "gametime" in your main script, use <gametime.dat set /p "gametime="
GAMETIME.BAT:
#echo off
set gametime=10:00
for /f "tokens=1,2 delims=:" %%a in ("%gametime%") do (
set hours=%%a
set mins=%%b
)
:loop
call :increase_gametime
timeout 5 >nul
goto :loop
:increase_gametime
set /a mins+=10
set /a hours=hours+mins/60
set /a mins=mins%%60
set gametime=%hours%:%mins%
title %gametime%
>gametime.dat echo %hours%:%mins%
Related
I'm trying to make a batch file that'll run in the background and shut my computer off when the regional time corresponds to a time I've set so that I can fix my sleep schedule.
However, I'm running into issues testing how to compare the current time to the time I've set as a variable.
I believe that it's due to the format that is returned by the time command and the format I entered not being the same.
I would like to enter a time in the 12-hour format and the computer shuts down at the designated time. But the time command returns a 24-hour format string unless paired with the /t switch.
This is what I currently have as test code that returns a printed line instead of shutting down my computer:
#echo off
set /p shutdownTime=What time would you like to shut down the computer?
:begin
set time=time /t
if "%time%" EQU "%shutdowmTime%" echo Time Confirmed
goto begin
I know that instead of an if statement in a loop I could probably do a for or while loop, but I'm honestly trying to keep it as simple as I can for my nocturnal smooth brain that woke up about 3 hours ago.
Any help is appreciated. Thank you.
Try this:
#echo off
FOR /F "tokens=* USEBACKQ" %%F IN (`time /t`) DO (
SET var=%%F
)
echo %var%
pause
will output 12hr time
#echo off
:resettime
echo make sure to Use caps for AM/PM and no spaces
set /p stime=What time would you like me to shutdown your computer?[example 03:45(AM/PM)]:
cls
echo your computer will shutdown at %stime%
:R
set /p p=would you like to change this time [y/n]:
if %p%==y goto resettime
if %p%==n goto loop
if not %p%==y goto R
if not %p%==n goto R
:loop
FOR /F "tokens=* USEBACKQ" %%F IN (`time /t`) DO (
SET var=%%F
)
set var=%var: =%
if %stime%==%var% goto endloop
goto loop
:endloop
shutdown /s
:a
set /p prompt=Would you like to abort shutdown [y/n]:
if %prompt%==y goto s
if not %prompt%==y goto a
:s
shutdown /a
I also quickly made the program described in your question. Its a bit buggy but it works.
I was trying to find a way to clear (CLS) a single line (see This Question), but found that the solutions, which involved moving the cursor, required extra software or modifications to files, which is not ideal.
However, I later noticed that the TIMEOUT command actually moves the cursor, which can be demonstrated with the following code:
#ECHO off
ECHO Notice how the cursor moves to the number.
ECHO Press [Ctrl]+[C] for an interesting result.
PAUSE
ECHO(
TIMEOUT 99999
PAUSE
If Ctrl+C is pressed after a couple of seconds, the "Terminate Batch Job" prompt overwrites the TIMEOUT output after the number. Any typing also continues to overwrite it.
What I am looking for, is any way to clear a line, change the line, or move the cursor somewhere, and also anything similar that could be useful. (I know this is a bit vague)
One idea was if it was possible to modify the stdout in such a way that the cursor still moved, it would at least be possible to get a changing number at one point in a custom line.
It might also be possible to asynchronously do both TIMEOUT and ECHO commands to have a similar effect to Ctrl+C.
Redirecting the TIMEOUT stdout to nul gives no LF character. This in conjunction with:
<nul SET /P var=#
REM echo without a LF character
...Could possibly be used to create progress bars.
Any thoughts, ideas, or other commands with similar effects are welcome.
Using answers from here you can have an increasing number printed.
It is important to insert the backspace character in place of insert_baskspace_here below.
You will need an editor that supports insertion of ASCII characters. I used Ultraedit but Notepad++ works too.
#echo off
setlocal enableextensions enabledelayedexpansion
set BS=insert_baskspace_here
Echo I printed 1 time
set /p "=I printed 2 times" <NUL
for /L %%I in (3,1,9) DO (
timeout /t 1 > nul
set /p "=!BS!!BS!!BS!!BS!!BS!!BS!!BS!%%I times" <NUL
)
The output starts as:
I printed 1 time
I printed 2 times
It changes each second and finishes with:
I printed 1 time
I printed 9 times
A few changes and you have a little progress spinner wheel:
#echo off
setlocal enableextensions enabledelayedexpansion
set BS=
set /p "=Processing.../" <NUL
for /L %%J in (0,1,9) DO (
for %%I in (-,\,^|,/,) DO (
timeout /t 1 > nul
set /p "=!BS!%%I" <NUL
)
)
I have a batch script that I desperately need help with. I use a batch script to grab files from folders and move them. The script sweeps the folders every 30 sec but you can "press a key to continue" also. I need to change it so I can press a specific key, doesn't matter what key, and have it GO TO the top location of my script to reset.
Below is a striped down version of what I currently have.
#echo off
set /p username=ENTER LOGIN:
echo.
:pc
echo 1 -- Flats
echo 2 -- Simple Tabletop
set /P rmFunc="Enter a choice: "
for %%I in (1 x) do if #%rmFunc%==#%%I goto run%%I
:run1
set pc=300
goto begin
:run2
set pc=400
goto begin
:begin
set studio=TT
set computer=Handbag_1
set setnumber=
set studiosetnumber=%studio%_%setnumber%
set delay_swch=5
set delay_loop=30
:bottom
echo logged in as: %username%
timeout /t %delay_loop%
GOTO BOTTOM
It is not possible to determine what key was pressed when using TIMEOUT, so that command is of no help.
You could use the CHOICE command with the /T (timeout) and /D (default) options instead. You can no longer simply press any key. Instead you can only press one key to restart, and another specific key to continue, or wait till the default value (continue) is returned. The biggest drawback is it no longer has a visual countdown.
echo Press C to Continue, or R to Restart
choice /c cr /d c /t 30 /n /m "The process will automatically continue in 30 seconds "
if errorlevel 2 goto pc
goto bottom
You could display a countdown timer by adding a third undocumented default option and setting the timeout to 1 second. If the default is returned, then it decrements the counter. Once the counter reaches 0 then the desired time has elapsed and you treat it as Continue.
I use the SET /P trick to display the prompt with a without a newline. I end with a carriage return so that the next prompt displays from the beginning of the same line.
The countdown timing will be a bit off, but it should be plenty good enough.
The carriage return variable must be defined and delayed expansion must be enabled near the top (before any loop label).
:: Define CR to hold a carriage return (0x0D)
for /f %%A in ('copy /Z "%~dpf0" nul') do set "CR=%%A"
:: Delayed expansion must be enabled to use the CR variable
setlocal enableDelayedExpansion
The timer code then becomes
set wait=15
:waitLoop
<nul set /p ="Press C to Continue, or R to Restart. Auto continue in %wait% seconds. !CR!"
choice /c 0cr /t 1 /d 0 >nul
if errorlevel 3 echo(&goto pc
if errorlevel 2 echo(&goto bottom
set /a wait-=1
if %wait% equ 0 echo(&goto bottom
goto :waitLoop
timeout does not return errorlevel if interrupted, so perhaps one way to solve this is to time timeout
#ECHO Off
SETLOCAL
SET /a "starttime=1%time:~-5,2%%time:~-2%"
timeout /t 30
SET /a "endtime=1%time:~-5,2%%time:~-2%"
IF %endtime% lss %starttime% SET /a endtime +=6000
SET /a elapsed=endtime - starttime
ECHO %elapsed%
GOTO :EOF
elapsed should contain the resultant time in tens-of-milliseconds. It's unlikely to be exactly 3000 for a 'no keypress' situation, but perhaps if %elapsed% gtr 2980 echo no keypress would suffice.
Note that I use a time format of hh:mm:ss.hh so if yours is different, you'd need to adjust the time substringing.
Since the target here is a timeout of about 30 seconds, the calculations can be performed on the seconds digits only. The values are accumulated as 1ss(.)hh which ensures that there is not a leading zero so set /a will not attempt to enter octal mode. Since it's entirely possible that the end time will be in the next minute, the adding of 6000 compensates by adding-in the minute (6000 tens-of-milliseconds)
Since it seems to be necessary to build the entire batch,
#echo off
set /p username=ENTER LOGIN:
echo.
:pc
echo 1 -- Flats
echo 2 -- Simple Tabletop
set /P rmFunc="Enter a choice: "
:
for %%I in (1 x) do if #%rmFunc%==#%%I goto run%%I
:run1
set pc=300
goto begin
:run2
set pc=400
goto begin
:begin
set studio=TT
set computer=Handbag_1
set setnumber=
set studiosetnumber=%studio%_%setnumber%
set delay_swch=5
set delay_loop=30
:bottom
echo logged in as: %username%
SET /a "starttime=1%time:~-5,2%%time:~-2%"
timeout /t %delay_loop%
SET /a "endtime=1%time:~-5,2%%time:~-2%"
IF %endtime% lss %starttime% SET /a endtime +=6000
SET /a elapsed=endtime - starttime
if %elapsed% leq 2980 goto ???
GOTO BOTTOM
And - well there I'd have to leave it. You are setting studio and setnumber to constants within your code. Are these somehow related to "Process Class?" If you want to re-enter this data, then you'd need ??? above to be begin - but you'd need to set /p those values (which you haven't shown.) As for the file sweep - there's nowhere in your code that shows this filesweep happening. The modifications I have indicated will allow you to press any key to interrupt the 30-second bottom loop and re-enter the data.
I have made a batch game where users can log in / register. But there is no point in having passwords if a person standing nearby can peep at the password. Normal password fields mask the characters with asterisks (*).
How can mask characters on a batch file?
I've seen this done on cmd before but I have no clue how.
You can use XCOPY for a hidden input, it can handle nearly all characters and you can also implement a backspace logic.
#echo off
setlocal EnableDelayedExpansion
call :input
echo(
echo '!input!'
if "!input!"=="password" echo OK
exit /b
:input
for /F "tokens=1 delims=# " %%a in ('"prompt #$H# & echo on & for %%b in (1) do rem"') do (
set "\b=%%a"
)
set "input="
:keyLoop
call :GetKey
if not defined key exit /b
if "!key!"=="!\b!" (
if defined input (
set "input=!input:~0,-1!"
<nul set /p ".=!\b! !\b!"
)
) ELSE (
<nul set /p ".=*"
set "input=!input!!key!"
)
goto :keyLoop
:GetKey
setlocal DisableDelayedExpansion
set "key="
for /F "usebackq delims=" %%L in (`xcopy /L /w "%~f0" "%~f0" 2^>NUL`) do (
if not defined key set "key=%%L"
)
(
endlocal
set "key=^%key:~-1%" !
exit /b
)
This code should be able to handle all characters, like ^!&%<>.
It's also possible to use backspace to delete the last entered character.
The line set "key=^%key:~-1%" ! seems odd, but it's used to escape the ! character with set "key=^!" ! in the delayed expansion context.
And to avoid problems for all other characters the last ! removes the caret, like in set "key=^A" ! will be evaluated to ``set "key=A"`
Ok, this is a bit different to what you may have had in mind, but that's you're fault for choosing batch for game dev.
The way I see it is you have 3 options:
Use an external program you self made in C#, C++, Python, [etc.]
Howver this requires an application to already do this for you (Which there probably is) or for you to have a knowledge in one of these languages
Use the choice command, to continuously take one key input and wait for the user to hit space to signify the end of the password
However this limits the password characters choice, and makes the program look ugly
Use 2 Batch threads, one that masks and tallies input while the other stores it to a variable.
This may be a bit dodgey at times, at would be a bit complicated but may be the only choice you have.
Now, as I was typing this an idea stuck my head on how to achieve this. Since it might take some time to test I thought I'd post the idea (as it seems to be a soloution to this problem, which has been around for a while).
Logic
One Batch Thread will simply use set /p to store all the input into a variable and upon completion will communicate to the other batch thread through the use of waitfor or a simple directory file.
Another Batch Thread would loop the pause >nul statement and would tally the number of times the pause statement is looped, printing out the appropriate amount of *'s. The other important job of this thread is to sense when the user has finished typing the password, upon which it exits.
Im starting to make this batch program now, but for now I'll just keep you informed of my idea so far.
Code
Login.bat
#echo off
Title Password Please:
:: This is the main code
REM This code relies on Masker.bat
REM SET password to be first and thrid letter,
REM of the day of the week.
set pass=%Date:~0,1%%Date:~2,1%
REM START Masker in the same window using /b tag and create hold.pass:
Echo 0 >%temp%\hold.pass
start /b Masker.bat "%pass%" *
REM Simply take input an leave the rest to Masker.bat
set /p pass_input=:
Echo 1 >>%temp%\hold.pass
cls
if /i "%pass%" NEQ "%pass_input%" (
Title Worng Password
Echo Wrong Password... Sorry.
Sleep 5
Exit
)
Pause > nul
REM Rest of Main game code is below or simply
:: START Main.bat & Exit
Masker.bat
#echo off
Title Password Please:
setlocal enabledelayedexpansion
:: This is not the main code
REM This code is called upon by Login.bat (or the Main.bat game code)
REM CREATE the variables "passlen" and "mask":
set password=%~1
set passlen=0
:miniloop
set /a passlen+=1
if "!password:~%passlen%,1!" NEQ "" goto :miniloop
set password=
set mask=%~2
if "%mask%" EQU "" set mask=*
REM MAIN loop
:loop
cls
for /l %%a in (1,1,%passlen%) do (<nul set /p=%mask%)
sleep -m 150
for /f "usebackq" %%a in ("%temp%\hold.pass") do (if "%%~a" EQU "1" Del %temp%\hold.pass & Exit)
goto :loop
It still needs some more improvements, but I've spent aroung 30 min on it with little success to make it dynamically tell you how many characters you have typed in.
Anyone cane take this up, be my guest. Everything else works fine
Mona
This works without pressing enter after input of the password.
If you enter the correct password, ok.
if you enter a wrong password, it will stop when you enter the 9th character (can be adapted).
It does not care about capitalization.
Problem: the password is stored as pure text in the code
#echo off
setlocal enabledelayedexpansion
set "s= abcdefghijklmnopqrstuvwxyz"
set p=
:loop
choice /C %s% /N >nul
set p=%p%!s:~%errorlevel%,1!&set /p =*<nul
if /i "%p%"=="secured" goto :right
if not "%p:~8,1%"=="" goto :wrong
goto :loop
goto :wrong
:right
echo you entered correct password: %p%
goto :eof
:wrong
echo you entered wrong password: %p%
goto :eof
You may use ReadFormattedLine subroutine for all kind of formatted input. For example, the command below read a password of 8 characters, display asterisks in the screen, and continue automatically with no need to press Enter:
call :ReadFormattedLine password="********" /M "Enter password (8 chars): "
This subroutine is written in pure Batch so it does not require any additional program, and it allows several formatted input operations, like read just numbers, convert letters to uppercase, etc. You may download ReadFormattedLine subroutine from Read a line with specific format.
I would like to start a program with a windows batch file. But the program should stop after a certain timeout value. For example: Run the program 60 seconds and stop it after 60 seconds.
Under Linux, there is this nice timeout command to do what I want. Windows has also a timeout command, but its just to pause a command, to delay its execution. Is there something else under Windows to do so ?
Setup: Windows 7, 64 Bit, Professional
start yourprogram.exe
timeout /t 60
taskkill /im yourprogram.exe /f
Bali C gave a concise and to the point answer.
I needed something a little more featureful and reusable.
Based on Bali C's Example. I came up with this.
If anyone should need the same as me.
your.bat
REM...
CALL STARTwaitKILL..bat /relative/path/your_program.exe
REM...
STARTwaitKILL.BAT
#ECHO OFF
IF[%1]==[] GOTO EOF
IF NOT EXIST %1 GOTO EOF
REM SET PRIORITY=/NORMAL
REM ADJUST PRIORITY, BELOWNORMAL LETS BATCH FILE RUN MORE SMOOTHLY
REM WITH A PROGRAM THAT CONSUMES MORE CPU. SEE ABOUT MAXWAIT BELLOW
SET PRIORITY=/BELOWNORMAL
REM SET PRIORITY=/LOW
REM 0 NORMAL WINDOW :: 1 NO WINDOW :: 2 MINIMIZED WINDOW
SET /A HIDDEN=1
REM MAXWAIT HERE IS MORE LIKE MINIMUM WAIT IN WINDOWS.
SET MAXWAIT=10
SET WAITCOUNT=0
SET ARGS=/I %PRIORITY%
IF %HIDDEN% EQU 1 SET ARGS=%ARGS% /B
IF %HIDDEN% EQU 2 SET ARGS=%ARGS% /MIN
START %ARGS% %1
:WAIT
IF %WAITCOUNT% GEQ %MAXWAIT% GOTO KILL_IT
TIMEOUT /T 1 > NUL
SET /A WAITCOUNT+=1
FOR /F "delims=" %%a IN ('TASKLIST ^| FIND /C "%~nx1"') DO IF %%a EQU 0 GOTO RUN_DONE
GOTO WAIT
:KILL_IT
TASKKILL /IM %~nx1 /F > NUL
:RUN_DONE
Could be fleshed out ore to take more arguments for priority and such, but I don't have the need for it. Shouldn't be hard to add.
Don't exist any command in Windows to delay an app or to set a timeout for an app
Timeout in Windows is for Delay the execution process of CMD/Batfile, nothing more utility.
You can use external tools for that, I don't remember the name of any now, so many underground software, sorry, but I remember that in the autoit official forum exists a similar commandline tool to launch an app setting the timeout,
and maybe in the tool NIRCMD, or ps2exec, check their help files, or someone inside the WAIK Kits.
This is the only you can do:
#Echo OFF
:: First launch the app in background mode, because some applications stops the execution of CMD.
Start /B ".\Dir\Your app.exe"
:: Then stay in background for a certain time
Timeout /T "Seconds"
:: Continue your code...
Pause&Exit
The start+timeout+taskkill waits exactly the given time. Since I needed to stop waiting if the process exits earlier, I created my own solution in C++.
The tuxliketimeout program mimics the GNU timeout. Feel free to download&compile from
https://github.com/cernoch/tuxliketimeout
In windows 10 the easiest way is with scriptrunner:
Demonstrate the timeout by running a pause command (this will kill the called process):
ScriptRunner.exe -appvscript cmd "/c" "pause" -appvscriptrunnerparameters -wait -timeout=20