How to make a batch SET /P statememt not require an enter - batch-file

I'm making my own console based off batch because I want more then what cmd offers but have the key features that batch has.
One of the most important things is to prompt the user for the command:
:prompt
#echo off
title JDOS command line
echo.
echo.
SET /P command="%FDIR%>"
rem SECTIONS/COMMANDS
rem /I means the if statement is not case-sensitive. USE IT AT ALL TIMES!
if /I "%command%"=="add" goto add
if /I "%command%"=="subtract" goto subtract
goto prompt
(This is just a small portion of all the options but you get the idea)
:add
title Calculator/Add
SET /P Add_A=Please enter the first number:
SET /P Add_B=Please enter the second number:
SET /A sum=%Add_A% + %Add_B%
echo The sum is %sum%
timeout /t 10 >nul
goto prompt
But this is timewasting and sort of idiotic (at least in my opinion).
So, can I execute goto add without the user pressing enter ?
Edit:
I'm thinking an approach similar to CHOICE but with the option to have more than 1 key be pressed (so for example instead of 1/2/3/4/ it would be restart/shutdown/lock/logoff/

I modified my accepted answer at this post and adjusted it for this request. Here it is:
#echo off
setlocal EnableDelayedExpansion
set "commands=add subtract"
for %%a in (%commands%) do set "com[%%a]=1"
for /F %%a in ('echo prompt $H ^| cmd') do set "BS=%%a"
for /F %%a in ('copy /Z "%~F0" NUL') do set "CR=%%a"
set "command="
:nextKey
set "key="
for /F "delims=" %%K in ('xcopy /W "%~F0" "%~F0" 2^>NUL') do if not defined key set "key=%%K"
if "!key:~-1!" equ "!CR!" goto endCommand
if "!key:~-1!" equ "!BS!" (
if defined command (
set "command=%command:~0,-1%"
set /P "=.!BS!!BS! !BS!!BS!" < NUL
)
) else if "!key:~-1!" neq " " (
set "command=%command%!key:~-1!"
set /P "=!key:~-1!" < NUL
if defined com[!command!] goto endCommand
)
goto nextKey
:endCommand
echo/
echo/
echo command read: "%command%"
Note: The mechanism used in this method does not allow to insert spaces! This code should be modified in large parts in order to read spaces.

Related

How do I disable user input in a batch-file?

Here's the code:
#echo off
color 0a
set /p object="Name an object (article included): "
set /p person="Name a person: "
set /p place="Name a place: "
echo %person% decided it was a good idea to take %object% to %place%. It was not.
set /p DUMMY=Hit Enter to proceed.
I would like to make it so that when the Hit Enter to proceed part shows up, you can't type anything, until you pressed Enter.
Ok. Perhaps you may be wrong when you said "it's possible the program will break" when the user enter "anything" as response in a set /P command. Anyway, this code do what you want:
#echo off
setlocal EnableDelayedExpansion
rem Get a CR
for /F %%a in ('copy /Z "%~F0" NUL') do set "CR=%%a"
set /P "=Hit Enter to proceed. " < NUL
:getKey
set "key="
for /F "delims=" %%K in ('xcopy /W "%~F0" "%~F0" 2^>NUL') do (
if not defined key set "key=%%K"
)
if "!key:~-1!" neq "!CR!" goto getKey
echo/
echo Proceeding...

Batch Script Variables - Pull from a single line of a text file with multiple lines of variable options

I'm trying to create a batch file that the user can use to connect with SCCM and RDP to PCs that are constantly connected to. I can do this easily with writing out the script for each PC but I would like to do this in a way that I have a text file with variables as I would do with a LOOP but I don't need a LOOP, I need to be able to select a single line of the text file.
Currently I have a list of options and I manually edit the script file with the options and the user selects a number to select the name but I need to remove all script so that the user doesn't accidentally modify the script, only the variables.
Sample text file - (Store user entered variables for both SCCM and RDP)
Variable1 Variable2 Variable3 Variable4
Description1 ComputerName1 ComputerUser1 ComputerPassword1
Description2 ComputerName2 ComputerUser2 ComputerPassword2
Description3 ComputerName3 ComputerUser3 ComputerPassword3
Description4 ComputerName4 ComputerUser4 ComputerPassword4
Description5 ComputerName5 ComputerUser5 ComputerPassword5
Description6 ComputerName6 ComputerUser6 ComputerPassword6
Sample SCCM Batch script -
(SCCM command line interface only allows computer name so I'd only be able to pull the name but I still want a single text file for both SCCM and RDP connections)
Variable1's listed from text file -
Description1
Description2
Description3
Description4
Description5
Description6
Make a selection: ((User enters Variable1))
sccm\CmRcViewer.exe "<variable2>" <-------from a specific line a user selects
Sample RDP Batch script - (I use the cmdkey to store the user/pass since mstsc command line interface only allows the name unless I do this first)
Variable1's listed from text file -
Description1
Description2
Description3
Description4
Description5
Description6
Make a selection: ((User enters Variable1))
cmdkey /generic:"<variable2>" /user:"<variable3>" /pass:"<variable4>" <-------from a specific line a user selects
mstsc /v:"<variable2>" /f <-------from a specific line a user selects
Any assistance is greatly appreciated. As a disclaimer, this is only being used by those in IT who has a decent knowledge of batch scripts, just trying to make it a tad easier to get to our PCs we are constantly accessing and those users we are constantly helping remotely...
This is a line selector I've made previously that builds an Array containing the value of each Line and allows scrolling and selection of the value via the choice command.
The :Load and :Extract labels are where the functions most relevant to your needs reside.
EDIT:
The stripped down components modified for just the output you seek - Using the safer form of input (Choice Command). Note that if the number of options exceeds 9, Set /P will need to be used - though input should be validated.
#Echo Off & Setlocal EnableDelayedExpansion
Set "lines=0"
Set "Options=E"
For /f "Skip=1 Tokens=* Delims=" %%A in (%~dp0\Choices.txt) do (
Set /A lines+=1
Set "line[!lines!]=%%A"
Set "Options=!Options!!lines!"
)
:extract
Cls
For /F "Tokens=1,2 Delims==" %%A in ('Set line[') Do (
Set "Option=%%~A"
Set "Option=!Option:line=!"
Echo !Option! %%B
)
For /F "Delims=" %%C in ('Choice /N /C %Options%') Do (
If "%%C" == "E" (Endlocal & Exit /B 0)
For /F "Tokens=2,3,4 Delims= " %%G in ("!line[%%C]!") Do cmdkey /generic:"%%~G" /user:"%%~H" /pass:"%%~I" & mstsc /v:"%%~G" /f
)
Goto :extract
An example of validating input if using Set /P
Set /P "INPUT=Selection: "
For /F "Delims=" %%C in ("!Input!") Do (
echo.%%C| findstr /R "[^0-9]" >nul 2>nul && Goto :extract
IF "%%C" == "0" (Endlocal & Exit /B) Else IF "%%C" GTR "%lines%" Goto :extract
For /F "Tokens=2,3,4 Delims= " %%G in ("!line[%%C]!") Do cmdkey /generic:"%%~G" /user:"%%~H" /pass:"%%~I" & mstsc /v:"%%~G" /f
)
Original
#Echo off & CD "%~dp0"
TITLE %~n0 & Setlocal
%= Remark =%
(Set LF=^
%= NewLine variable to split set /p input line =%)
::: / Creates variable /AE = Ascii-27 escape code.
::: - http://www.dostips.com/forum/viewtopic.php?t=1733
::: - https://stackoverflow.com/a/34923514/12343998
:::
::: - /AE can be used with and without DelayedExpansion.
Setlocal
For /F "tokens=2 delims=#" %%a in ('"prompt #$H#$E# & echo on & for %%b in (1) do rem"') do (
Endlocal
Set "/AE=%%a"
)
::: \
%= create blank batch file to store and Selectively retieve variables with =%
If not Exist "inputURLlog.log" (Break>inputURLlog.log & Goto :main)
For %%A in ( "%/AE%[36m[%/AE%[34mN%/AE%[36m]ew" , "[%/AE%[34mL%/AE%[36m]oad%/AE%[0m")Do Echo.%%~A
Choice /N /C nl >nul
If errorlevel 2 (Goto :load)
Goto :Main
:Input <VarName>
Set "variable=%~1"
Setlocal EnableDelayedExpansion
:Validate
%= allow input of variable, test input, store for reuse. =%
Echo(%/AE%[35m
Set /P "input=!variable!!LF!%/AE%[36m{> %/AE%[33m"
IF "!input!"=="" (
Echo(%/AE%[31m!variable! required.
Goto :Validate
)
If "!input!"=="" (Echo(%/AE%[31m!variable! required. & Goto :Validate)
IF /I "!input!"=="load" (Goto :load)
%= Url Validation - Optional =%
(ping !input!)>nul || (Echo Invalid url & Endlocal & Goto :main)
ECHO(!input!>>inputURLlog.log
Endlocal
Exit /B
:main
Call :Input Url
Goto :main
:load
Setlocal EnableDelayedExpansion
Set lines=0
For /f "Tokens=* Delims=" %%A in (inputURLlog.log) do (
Set /A lines+=1
Set "line[!lines!]=%%A"
)
REM Set "#=%lines%" & REM start from newest entry
Set "#=1" & REM start from oldest entry
Echo %#%
:extract
For %%A in (!#!) do (
Cls
Title Option %%A of !lines!
Echo(Url: !line[%%A]!
For %%B in ("%/AE%[36m[%/AE%[34mS%/AE%[36m]elect" "[%/AE%[34mN%/AE%[36m]ext" "[%/AE%[34mL%/AE%[36m]ast%/AE%[0m")Do Echo.%%~B
Choice /N /C LNS /M ""
If "!errorlevel!"=="3" (Set "Url=!line[%%A]!" & Goto :Selected)
If "!errorlevel!"=="2" (IF not !#! GEQ !lines! (Set /A #+=1) Else (Set "#=1"))
If "!errorlevel!"=="1" (IF not !#! LEQ 1 (Set /A #-=1) Else (Set "#=%lines%"))
)
Goto :extract
%= Demonstrate that variable has been reloaded =%
:Selected
Echo( Selected Url = !Url!
Pause >nul
#echo off
setlocal enabledelayedexpansion
set x=0
for /f "skip=1 tokens=1-4" %%i in (%~dp0\Choices.txt) do (
call set /a x+=1
call set item.%%x%%.1=%%i
call set item.%%x%%.2=%%j
call set item.%%x%%.3=%%k
call set item.%%x%%.4=%%l
)
for /l %%i in (1,1,%x%) do (
call echo %%i. !item.%%i.1!
)
echo. & set /p sel=Enter Selection:
cmdkey /generic:"!item.%sel%.2!>" /user:"!item.%sel%.3!" /pass:"!item.%sel%.4!"
mstsc /v:"!item.%sel%.2!" /f

Batch choice alternative for detecting key without pause

The question is: is here any way to detect keypress in batch without pausing entire script for scripts like chat, games etc? For now I know about useful command called xcopy. I use it to detect and extract pressed key such as Enter. But it pauses entire script and waits for confirmation, while chose may not pause script, but unable to do silent invalid key as well as detecting specific ones
It's not simple with pure batch, but possible.
This is a sample that uses two threads.
The first thread :keyCheck waits for a key.
The second thread :mainFunc counts until a key is pressed.
#echo off
setlocal DisableDelayedExpansion
set "func=%~0"
for /F "delims=\" %%X in ("%func:*\=%") do set "func=%%X"
if ":" == "%func:~0,1%" (
goto %func%
)
( "%~d0\:keyCheck\..%~pnx0" ) > lock.tmp | "%~d0\:mainFunc\..%~pnx0"
echo Ende
exit /b
REM *** Thread1 - waiting for key
:keyCheck
for /f skip^=1^ delims^=^ eol^= %%A in ('replace.exe ? . /u /w') do for /f delims^=^ eol^= %%B in ("%%A") do (
set key=%%B
)
exit /b
REM *** Thread2 - Counting up
:mainFunc
setlocal EnableDelayedExpansion
for /F %%# in ('copy /Z "%~dpf0" NUL') do set "CR=%%#"
set "lastTime="
set cnt=0
:loop
set /a cnt+=1
set /p "=Stop with any key !cnt! !CR!" < nul
call :waitOrStop
goto :loop
:waitOrStop
REM Check if a key was pressed, then the lock is released
(
(
rem
) 2> lock.tmp && (
echo(
exit
)
) 2> nul
set "now=%time:~-2%"
if "!now!" NEQ "!lastTime!" (
set "lastTime=!now!"
exit /b
)
goto :waitOrStop
While it is not at all straightforward, the site Dostips.com has a full implementation of the game "Snake" using nothing but Batch, including non-blocking input.
Essentially, the batchfile spawns a second command prompt, which is blocking on input. When input is received, it is routed to the first, "main" program which polls the input file.
Like I said, not straightforward or simple, but it is do-able.
Although possible, there is not a simple way to do that using pure Batch commands. The simplest way is use a third party .exe program specifically designed to do so, like my GetKey.exe auxiliary file. This program get a key from keyboard and returns via ERRORLEVEL a value that indicate the key pressed. All keys are processed: ASCII characters are returned as positive values and extended keys (function keys, cursor control keys, etc) as negative values. If /N switch is given, GetKey.exe no waits: if a key was not pressed the value returned is zero.
This is a very simple example program that use GetKey.exe auxiliary file:
#echo off
setlocal EnableDelayedExpansion
rem Simple example of GetKey.exe auxiliary program to detect keys pressed
rem Get a Return (ASCII 13) CR character
for /F %%a in ('copy /Z "%~F0" NUL') do set "CR=%%a"
cls
echo Press a key at any moment; press ESC key to end
echo/
set i=0
:loop
set /A i+=1
set /P "=%i%!CR!" < NUL
GetKey /N
if %errorlevel% equ 0 goto loop
echo/
echo Key pressed: %errorlevel%
if %errorlevel% neq 27 goto loop
You may download GetKey.exe auxiliary program from this site; you may also download SHOWKEYCODES.BAT program that show the codes returned by GetKey.exe for all keys in keyboard, including Shift-, Ctrl- and Alt- combinations.
PS - If you are reluctant to use a third-party .exe program, just think that the original choice command is also an .exe file with a 35 KB size, but my GetKey.exe file is just 1536 bytes size. You may review several of my auxiliary .exe files and the replies posted by users of these programs at the same link.
Another multithread method, this time using Xcopy to capture input.
Handles all ASCII printable characters in the range 32 ~ 126, as well as TAB, Carriage Return and Backspace.
#Echo off
REM on relaunch, directs execution to the target label.
If not "%~1"=="" Goto:%1
REM initialize variables for the controller launcher
Set "QuitKey={BACKSPACE}"
Set "SignalFile=%TEMP%\%~n0_signal.dat"
REM Pipe the output of the function XCOPYCONTROLLER to Game to facilitate non blocking input.
Start /Wait /B "" "%~F0" XCOPYCONTROLLER 1>"%SignalFile%" | "%~F0" GAME <"%SignalFile%" 2> nul
REM end of controller launcher. Game has been quit.
Endlocal & Goto:Eof
:GAME
REM enable EDE environment to facilitate the use of posion characters.
REM More advanced gameloops use an infinite for /l loop to iterate through game logic
REM as it is parsed more efficiently by cmd.exe's interpreter.
REM such loops Require EDE to expand variables with their current value.
Setlocal EnableDelayedExpansion
:GAMELOOP
REM your game loop goes here.
Cls
Set /p "key="
If Defined key Title Lastkey= "!Key!". Press !Quitkey! to exit
Echo(%TIME%
If "!Key!"=="quit" EXIT
Set "key="
Goto:GAMELOOP
=======================================================
:XCOPYCONTROLLER by T3RRY
Setlocal EnableExtensions DISABLEdelayedExpansion
REM define unprintable characters
(Set LF=^
%= Do Not Modify. Linefeed Variable =%)
%= Escape =% for /f "Delims=" %%e in ('Echo Prompt $E^|cmd') Do Set "\E=%%e"
%= Tab =% for /f "delims= " %%T in ('robocopy /L . . /njh /njs' )do set "TAB=%%T"
%= Carriage Return =% for /f %%C in ('copy /Z "%~dpf0" nul') do set "CR=%%C"
%= BackSpace =% for /F "delims=#" %%B in ('"prompt #$H# &echo on &for %%b in (1) do rem"') do Set "BS=%%B"
Set "BS=%BS:~0,1%"
%= SUB =% copy nul sub.tmp /a > nul
for /F %%a in (sub.tmp) DO (
set "sub=%%a"
)
del sub.tmp
(TITLE )
<nul Set /P "=Press any Key to start"
REM Environment handling allows use of ! key
For /l %%C in () do (
Set "Key="
for /f "delims=" %%A in ('%SystemRoot%\System32\xcopy.exe /w "%~f0" "%~f0" 2^>nul') do If not Defined Key (
set "key=%%A"
Setlocal ENABLEdelayedExpansion
set "key=!KEY:~-1!"
If "!key!" == "!QuitKey!" (
<nul Set /P "=quit"
EXIT
) Else If "!Key!" == "%BS%" (
If "!QuitKey!" == "{BACKSPACE}" (
<nul Set /P "=quit"
EXIT
)
<nul Set /p "={BACKSPACE}"
) Else If "!Key!" == "!CR!" (
If "!QuitKey!" == "{ENTER}" (
<nul Set /P "=quit"
EXIT
)
<nul Set /p "={ENTER}"
) Else If "!Key!" == "!TAB!" (
If "!QuitKey!" == "{TAB}" (
<nul Set /P "=quit"
EXIT
)
<nul Set /p "={TAB}"
) Else (%= Echo without Linefeed. Allows output of = Key and Space =%
1> %~n0txt.tmp (echo(!Key!!sub!)
copy %~n0txt.tmp /a %~n0txt2.tmp /b > nul
type %~n0txt2.tmp
del %~n0txt.tmp %~n0txt2.tmp
)
Endlocal
)
)

How to map numbers to a variable

I have the following script but I want to map the numbers to the variable but do not know how to. So if a user enters 0, I want it to search for the event name NewUser.
#echo off
mode con:cols=40 lines=40
set /p customerID="Enter Customer ID: "
CLS
:MENU
ECHO.
ECHO ...............................................
ECHO PLEASE SELECT THE EVENT FROM THE MENU BELOW
ECHO ...............................................
ECHO.
ECHO Event Code Event Name
ECHO.
ECHO 0 NewUser
ECHO 1 ExistingUser
ECHO 2 EmailAdded
ECHO 3 AccountProblem
ECHO 4 Lost
ECHO.
SET /P event=Type the event code and then press ENTER:
IF %event%==0 set event=NewUser GOTO find
IF %M%==1 set event=ExistingUser GOTO find
IF %M%==2 set event=EmailAdded GOTO find
IF %M%==3 set event=AccountProblem GOTO find
IF %M%==4 set event=Lost GOTO find
pause
:find
pause
setlocal enableextensions disabledelayedexpansion
pause
set "sourceFolder=C:\test"
set "targetFolder=C:\test2"
pause
set "customerID=%customerID%"
set "NewUser=%Event%"
pause
for /f "delims=" %%a in ('
findstr /m /s /l /c:"%customerID%" "%sourceFolder%\*"
^| findstr /f:/ /m /l /c:"%event%"
') do (
copy "%%~fa" "%targetFolder%"
)
pause
The first version of your code was closer to correct solution than current one; you need to use two nested for /F loops as follows:
for /f "delims=" %%a in ('
findstr /I /m /s /l /c:"%customerID%" "%sourceFolder%\*.txt"
') do for /f "delims=" %%A in ('
findstr /I /m /l /c:"%event%" "%%~fa"
') do (
rem 'copy' command is merely displayed using ECHO for debugging purposes
ECHO copy "%%~fa" "%targetFolder%"
)
Next commented code snippet could help to improve the script:
#ECHO OFF
SETLOCAL EnableExtensions DisableDelayedExpansion
set "customerID="
:customerID
set /p customerID="Enter Customer ID: "
if not defined customerID goto :customerID
REM instead of above test, you could apply next statement about `set /P`:
REM If the user does not enter anything (just presses return)
REM then the variable will be unchanged and an ERRORLEVEL will be set.
rem CLS
:MENU
ECHO.
ECHO ...............................................
ECHO PLEASE SELECT THE EVENT FROM THE MENU BELOW
ECHO ...............................................
ECHO.
ECHO Event Code Event Name
ECHO.
ECHO 0 NewUser
ECHO 1 ExistingUser
ECHO 2 EmailAdded
ECHO 3 AccountProblem
ECHO 4 Lost
ECHO.
REM SET /P M=Type the event code and then press ENTER:
choice /C 01234 /M "Type the event code"
REM 0 means that an user's reply to "Terminate batch job (Y/N)?" was not "y"
IF %ERRORLEVEL% EQU 0 echo "Ctrl-C" or "Ctrl-Break" pressed&goto :NoSearch
REM 255 means another error
IF ERRORLEVEL 255 goto :MENU
REM ERRORLEVEL number Specifies a true condition if the last program run
REM returned an exit code EQUAL TO OR GREATER THAN the number
REM specified.
IF ERRORLEVEL 1 set "event=NewUser"
IF ERRORLEVEL 2 set "event=ExistingUser"
IF ERRORLEVEL 3 set "event=EmailAdded"
IF ERRORLEVEL 4 set "event=AccountProblem"
IF ERRORLEVEL 5 set "event=Lost"
REM Note that in above code, ERRORLEVEL parameters are tested in INCREASING order
REM Used only in this special case
REM (no need of GOTO statement, 'event' variable is set correctly)
REM
REM although CHOICE /? says:
REM When you use ERRORLEVEL parameters in a batch program,
REM list them in decreasing order.
:NOTE
set "sourceFolder=D:\test"
set "targetFolder=D:\test2"
rem ??? set "customerID=%customerID%"
rem ??? set "event=%event%"
rem debugging output
echo looking for "customerID=%customerID%" "event=%event%"
for /f "delims=" %%a in ('
findstr /I /m /s /l /c:"%customerID%" "%sourceFolder%\*.txt"
') do for /f "delims=" %%A in ('
findstr /I /m /l /c:"%event%" "%%~fa"
') do (
rem 'copy' command is merely displayed using ECHO for debugging purposes
ECHO copy "%%~fa" "%targetFolder%"
)
:NoSearch
pause
Change your For loop like this and retest:
FOR /F "DELIMS=" %%A IN (
'FINDSTR/MSC:"%customerID%" "%sourceFolder%\*"^|FINDSTR/MIF:/ /C:"%event%"'
) DO COPY "%%A" "%targetFolder%"
EDIT
I have added a modified version of your script to include the new requirement of a three digit event code. Just adjust it's value in the script as necessary, (lines nineteen to twenty three).
#ECHO OFF
MODE CON:COLS=52 LINES=40
SETLOCAL ENABLEEXTENSIONS DISABLEDELAYEDEXPANSION
(SET sourceFolder=C:\test)
(SET targetFolder=C:\test2)
SET /P "customerID=Enter Customer ID: "
:MENU
CLS
ECHO=
ECHO= ..................................................
ECHO= PLEASE SELECT THE OPTION FROM THE EVENT MENU BELOW
ECHO= ..................................................
ECHO=
ECHO= Option Event Name Event Code
ECHO=
ECHO. 1. NewUser A00
ECHO. 2. ExistingUser A01
ECHO. 3. EmailAdded A02
ECHO. 4. AccountProblem A03
ECHO. 5. Lost A04
ECHO=
CHOICE /C 12345 /M "CHOOSE AN OPTION"
SET "Option=%ERRORLEVEL%"
FOR /F "TOKENS=1-4 DELIMS=. " %%A IN ('FINDSTR/BC:"ECHO. " "%~f0"'
) DO IF "%%B"=="%Option%" (SET "Name=%%C" & SET "Code=%%D")
FOR /F "DELIMS=" %%A IN (
'FINDSTR/MISC:"%customerID%" "%sourceFolder%\*"^|FINDSTR/MIF:/ /C:"%Name%"'
) DO COPY "%%A" "%targetFolder%"
PAUSE
Please make sure that %sourceFolder% is a full path and %targetFolder% already exists, (see line six).

Typing text with not yet (but will be) defined variables in batch

So i want to create typing text for a Turn Based RPG (in batch), where you have a person controlling almost everything that interacts with the players.
I want it so when everyone's turn is over, it will display what everyone did, but in a dramatic way.
Now some of us know
for %%i in (h e l l o) do (set /p a=%%i<nul & ping 0.0.0.0 -n 2.5>nul 2>&1)
but I want to have a variable do this using
set /p Write=<Write.txt
so i can have something like for %%i in (%write%) do (set /p a=%%i<nul & ping 0.0.0.0 -n 2.5>nul 2>&1)
to make it write one letter at a time.
Thanks!
The Batch file below use an interesting trick I borrowed from this post that convert the Ascii (1-byte) characters into Unicode 2-bytes characters via /U switch of cmd.exe (inserting a zero-byte between characters), and then split the zero-bytes in individual lines via find command:
#echo off
setlocal
echo Hello, World!> Write.txt
for /F %%a in ('echo prompt $H^| cmd') do set "BS=%%a"
for /F "delims=" %%i in ('cmd /D /U /C type Write.txt ^| find /V ""') do (
set /P "=X%BS%%%i" < NUL
ping localhost -n 2 > NUL
)
EDIT: New version added
I modified previous code to show several lines in the right way; it also use JScript's sleep method in order to use variable delay intervals between each character, this point results in an output appearing in a more dramatic way.
#if (#CodeSection == #Batch) #then
#echo off
(
echo Hello, World!
echo The World is ending!
) > Write.txt
for /F %%a in ('echo prompt $H^| cmd') do set "BS=%%a"
for /F "delims=" %%a in (Write.txt) do (
for /F "delims=" %%i in ('cmd /D /U /C set /P "=%%a"^<NUL ^| find /V ""') do (
set /P "=X%BS%%%i" < NUL
REM ping localhost -n 3 > NUL
cscript //nologo //E:JScript "%~F0"
)
echo/
)
goto :EOF
#end
// JScript section: wait a random number of milliseconds between 0 and 300
WScript.Sleep(300*Math.random());
This is a version of Ghost typer that uses a variable, to display text on a screen in a way that a person might type it.
#echo off
:: Ghost typer - variable version
:: shows text in a variable on the screen in a way that a person might type it.
:: Do not use " in the text to be printed, replace them with '
:: Adjust speed variable - higher numbers increase typing speed - default=3
set speed=6
:: backspace variable is used in the printing routine
for /f %%a in ('"prompt $H&for %%b in (1) do rem"') do set "BS=%%a"
set "line=Your dog was eaten by a red winged dragon!"
call :begin
set "line=Two sloths ate all your chocolate!"
call :begin
set "line=A genie appears, and grants you 4 wishes...."
call :begin
set "line=How many woodchucks does it take?"
call :begin
pause>nul
goto :EOF
:begin
set num=0
:type
call set "letter=%%line:~%num%,1%%"
set "delay=%random%%random%%random%%random%%random%%random%%random%"
set "delay=%delay:~-6%"
if not "%letter%"=="" set /p "=a%bs%%letter%" <nul
for /L %%b in (1,%speed%,%delay%) do rem
if "%letter%"=="" echo.&goto :EOF
set /a num+=1
goto :type
To print the characters one by one of an arbitrary string, you could use the following:
#echo off
rem define string to print:
set "WRITE=Hello world!"
setlocal EnableDelayedExpansion
for /L %%I in (0,1,8191) do (
set "CHAR=!WRITE:~%%I,1!"
rem if "!WRITE:~%%I,2!"=="!CHAR! " set "CHAR=!CHAR! "
if "!CHAR!"=="" goto :SKIP
< nul set /P "DUMMY=!CHAR!"
> nul 2>&1 ping 127.0.0.1 -n 2
)
:SKIP
endlocal
As you will notice, the SPACE within the string in WRITE is not printed, because set /P does not print any (leading) spaces in the prompt string. To work around this, remove the rem in front of the if inside of the for loop. Actually this previews the next character and appends it to the current one in case it is a space, as set /P prints trailing spaces.
#echo off
setlocal enabledelayedexpansion
for /f %%A in ('"prompt $H &echo on &for %%B in (1) do rem"') do set BS=%%A
set /P string=<write.txt
call :StrLen "%string%" _len1
for /L %%A in (0,1,%_len1%) do (
set "substring=!string:~%%A,1!"
set /p "=.%BS%!substring!" <nul
> nul 2>&1 ping 127.0.0.1 -n 1
)
echo.
pause
GOTO :EOF
REM Subroutine to return the length of a string variable
:StrLen [string] [len-var]
set "_str=A%~1" & set "_len=0"
for /L %%A in (12,-1,0) do (set /a "_len|=1<<%%A" & for %%B in (!_len!) do if "!_str:~%%B,1!"=="" set /a "_len&=~1<<%%A")
set /a %~2=%_len%
exit /b

Resources