I've created a batch/cmd file which executes correctly, but I would like to add a "validation" layer to check for correct input.
The input should be in the format of LETTER-LETTER-######## (Eight Numbers)
I'm more of a Bash person myself so I'm a little lost.
Here is a basic version of what I am using.
echo Please Input like so XY########
set /P INPUT=Type input: %=%
Ok. Here we go...
There is no way to do what you want if you read the input via set /P command. In this case you may test the input afterwards and repeat it until be correct...
To check the input at same time it is being typed you need to read and test each character individually. There are several ways to do that. The simplest one is based on choice command:
#echo off
setlocal EnableDelayedExpansion
echo Please Input like so XY########
set /P "=Type input: " < NUL
set "INPUT="
rem Get two *UPPERCASE* letters
set "letter= ABCDEFGHIJKLMNOPQRSTUVWXYZ"
for /L %%i in (1,1,2) do (
choice /C %letter% /N > NUL
for %%l in ("!errorlevel!") do set "INPUT=!INPUT!!letter:~%%~l,1!"
set /P "=!INPUT:~-1!" < NUL
)
rem Get eight digits
set "digit= 0123456789"
for /L %%i in (1,1,8) do (
choice /C %digit% /N > NUL
for %%l in ("!errorlevel!") do set "INPUT=!INPUT!!digit:~%%~l,1!"
set /P "=!INPUT:~-1!" < NUL
)
echo/
echo INPUT = "%INPUT%"
In this code:
Any letter pressed is converted to uppercase. This behavior may be cancelled including both upcase and lowcase letters in letter variable and adding /CS switch to choice command.
The last character input can not be deleted.
The input is automatically completed after the last character is input. No final ENTER key is needed.
If you want not this behavior and need more precise control on the input characters, then you must use another method; for example, reading the keys via xcopy trick. The link posted by Squashman above is an ample example on how to do that...
Aacini's answer also forces valid user input vs validating retroactilvey, his answer is less code and more "readable" IMO. I will be using his answer, but I figured I'd share this method.
I asked to "retroactively" validate user input, but #Squashmans commented URL forces valid user input in the first place.
https://www.dostips.com/forum/viewtopic.php?t=5775
Here is the "sanitized code" that I ended up with.
#echo off
#cls
::::START -- Section Blocks User from Inputting Invalid Data::::
setlocal
set "thisFile=%~F0"
call :ReadFormattedLine INPUT="__########" /M "Enter Input in Form XY########: "
echo/
:ReadFormattedLine var="mask" [/M "message"] [/P] [/F /W /A]
if "%~2" equ "" echo ERROR: Missing parameters & exit /B 1
setlocal EnableDelayedExpansion
set "var=%~1"
set "mask=%~2"
shift & shift
set "message="
if /I "%1" equ "/M" set "message=%~2" & shift & shift
set "password="
if /I "%1" equ "/P" set "password=1" & shift
set "switch=%~1"
set quote="
set "digit= 0 1 2 3 4 5 6 7 8 9 "
set "letter= A B C D E F G H I J K L M N O P Q R S T U V W X Y Z "
set "alphaNum=%digit%%letter%"
set "fmt=#_+?#"
set "show=$/\()[]:;,.- %digit: =%%letter: =%"
for /F %%a in ('copy /Z "%thisFile%" NUL') do set "CR=%%a"
for /F %%a in ('echo prompt $H ^| cmd') do set "BS=%%a" & set "SP=.%%a "
< NUL (
set /P "=%message%"
for /F "eol=| delims=" %%a in ('cmd /U /C echo !mask!^| find /V ""') do (
if "!fmt:%%a=!" neq "%fmt%" (
set /P "=Û"
) else if "%%a" neq " " (
set /P "=%%a"
) else (
set /P "=!SP!"
)
)
set /P "=!SP!!CR!%message%"
)
set "input="
set /A i=0, key=0
goto checkFormat
:nextKey
set "key="
for /F "delims=" %%a in ('xcopy /W "%thisFile%" "%thisFile%" 2^>NUL') do if not defined key set "key=%%a"
if "!key:~-1!" neq "!CR!" goto endif
if /I "%switch%" equ "/A" goto nextKey
if /I "%switch%" neq "/F" goto check/W
:nextField
set "format=!mask:~%i%,1!"
if "%format%" equ "" goto endRead
if "!fmt:%format%=!" equ "%fmt%" goto checkFormat
set /P "=Û" < NUL
set "input=%input% "
set /A i+=1
goto nextField
:check/W
if /I "%switch%" neq "/W" goto checkEmpty
if %i% equ 0 goto endRead
if "%format%" equ "" goto endRead
goto nextKey
:checkEmpty
if %i% gtr 0 goto endRead
goto nextKey
:endif
set "key=!key:~-1!"
if "!key!" equ "!BS!" (
if %i% gtr 0 (
if "%format%" equ "" (
set /P "=!SP!!BS!!BS!Û!BS!" < NUL
) else (
set /P "=Û!BS!!BS!Û!BS!" < NUL
)
set "input=%input:~0,-1%"
set /A i-=1
if !i! equ 0 set key=0
)
goto checkFormat
)
if "%format%" equ "" goto nextKey
if "!key!" equ "=" goto nextKey
if "!key!" equ "!quote!" goto nextKey
if "%format%" equ "#" ( rem Any digit
if "!digit: %key% =!" equ "%digit%" goto nextKey
) else if "%format%" equ "_" ( rem Any letter
if "!letter: %key% =!" equ "%letter%" goto nextKey
) else if "%format%" equ "+" ( rem Any letter, convert it to uppercase
if "!letter: %key% =!" equ "%letter%" goto nextKey
for %%a in (%letter%) do if /I "!key!" equ "%%a" set "key=%%a"
) else (
rem Rest of formats are alphanumeric: ? #
if "!alphaNum: %key% =!" equ "%alphaNum%" goto nextKey
if "%format%" equ "#" ( rem Convert letters to uppercase
for %%a in (%letter%) do if /I "!key!" equ "%%a" set "key=%%a"
) else if "%format%" neq "?" echo ERROR: Invalid format in mask: "%format%" & exit /B 2
)
)
if defined password (
set /P "=*" < NUL
) else (
set /P "=%key%" < NUL
)
set "input=%input%%key%"
:nextFormat
set /A i+=1
:checkFormat
set "format=!mask:~%i%,1!"
if "%format%" equ "" (
if /I "%switch%" equ "/A" goto endRead
if /I "%switch%" equ "/M" goto endRead
goto nextKey
)
if "!show:%format%=!" neq "%show%" (
if "!key!" equ "!BS!" (
if "%format%" neq " " (
set /P "=%format%!BS!!BS!Û!BS!" < NUL
) else (
set /P "=!SP!!BS!!BS!Û!BS!" < NUL
)
set "input=%input:~0,-1%"
set /A i-=1
if !i! equ 0 set key=0
goto checkFormat
) else (
if "%format%" neq " " (
set /P "=%format%" < NUL
) else (
set /P "=!SP!" < NUL
)
set "input=%input%%format%"
goto nextFormat
)
)
if "%input:~-1%!key!" equ " !BS!" (
set /P "=Û!BS!!BS!" < NUL
set "input=%input:~0,-1%"
set /A i-=1
goto checkFormat
)
goto nextKey
:endRead
echo/
endlocal & set "%var%=%input%"
echo %INPUT%
pause
exit /B
Related
I am trying to use For Loops that will start and end based on values entered by user in batch. However, when using the user input variables, the loop fail to work. May I know what have I done wrong and how do I correct it? Thanks in advance!
P.S. I have tried both ! and %
Here's the my source code which shows the for loop which is having problem:
setlocal EnableDelayedExpansion
set /p sy="Enter start year (e.g. 2020): "
set /p sm="Enter start month (e.g. 08): "
set /p ey="Enter end year (e.g. 2020): "
set /p em="Enter end month (e.g. 08): "
echo ***LIST OF MISSING FILES FROM %sm% %sy% to %em% %ey%*** > checkFile_%SUBFILENAME%.txt
for /L %%y in (%sy%,1,%ey%) do (
for /L %%m in (1,1,%maxMonth%) do (
if %%m leq 9 set month=0%%m
if %%m gtr 9 set month=%%m
if %%y equ %sy% if !month! leq %sm% (
goto :continue
)
if %%y equ %ey% if !month! equ %em% (
goto :breakloop
) else (
call :DaysOfMonth %%y !month!
set maxDay=!errorlevel!
echo Days Of Month !month!: !maxDay!
Here's the full script:
setlocal EnableDelayedExpansion
set maxHour=23
set maxMonth=12
set missing=0
set /p sy="Enter start year (e.g. 2020): "
set /p sm="Enter start month (e.g. 08): "
set /p ey="Enter end year (e.g. 2020): "
set /p em="Enter end month (e.g. 08): "
set CUR_YYYY=%date:~10,4%
set CUR_MM=%date:~4,2%
set CUR_DD=%date:~7,2%
set CUR_HH=%time:~0,2%
if %CUR_HH% lss 10 (set CUR_HH=0%time:~1,1%)
set CUR_NN=%time:~3,2%
set CUR_SS=%time:~6,2%
set CUR_MS=%time:~9,2%
set SUBFILENAME=%CUR_YYYY%%CUR_MM%%CUR_DD%-%CUR_HH%%CUR_NN%%CUR_SS%
echo ***LIST OF MISSING FILES FROM %sm% %sy% to %em% %ey%*** > checkFile_%SUBFILENAME%.txt
for /L %%y in (%sy%,1,%ey%) do (
for /L %%m in (1,1,%maxMonth%) do (
if %%m leq 9 set month=0%%m
if %%m gtr 9 set month=%%m
if %%y equ %sy% if !month! leq %sm% (
goto :continue
)
if %%y equ %ey% if !month! equ %em% (
goto :breakloop
) else (
call :DaysOfMonth %%y !month!
set maxDay=!errorlevel!
echo Days Of Month !month!: !maxDay!
set missingMonth=0
for /L %%d in (1,1,!maxDay!) do (
if %%d leq 9 set day=0%%d
if %%d gtr 9 set day=%%d
for /f "tokens=1*" %%i in ('PowerShell -Command "& {Get-Date "!day!/!month!/%%y" -format "ddd_MMM_dd"}"') do (
for /L %%f in (0,1,!maxHour!) do (
if %%f leq 9 set hour=0%%f
if %%f gtr 9 set hour=%%f
if not exist "%%i_!hour!_00_00_%%y.enf" (
echo Missing: %%i_!hour!_00_00_%%y.enf
echo Missing: %%i_!hour!_00_00_%%y.enf >> checkFile_%SUBFILENAME%.txt
set /A missing = missing+1
set /A missingMonth = missingMonth+1
)
)
)
)
)
echo NUMBER OF FILES MISSING FOR !month!: !missingMonth!
echo ***NUMBER OF FILES MISSING FOR !month!: !missingMonth!*** >> checkFile_%SUBFILENAME%.txt
echo. >> checkFile_%SUBFILENAME%.txt
:continue
)
)
:breakloop
echo TOTAL NUMBER OF FILES MISSING FROM %sm% %sy% to %em% %ey%: %missing%
echo. >> checkFile_%SUBFILENAME%.txt
echo ***TOTAL NUMBER OF FILES MISSING FROM %sm% %sy% to %em% %ey%*** >> checkFile_%SUBFILENAME%.txt
pause
:DaysOfMonth Year Month
setlocal DisableDelayedExpansion
set /a "yy = %~1, mm = 100%~2 %% 100"
set /a "n = 30 + !(((mm & 9) + 6) %% 7) + !(mm ^ 2) * (!(yy %% 4) - !(yy %% 100) + !(yy %% 400) - 2)"
endlocal &exit /b %n%
I'm trying to compare a sequence of 9 numbers (separated by ,) using a batch file.
The comparison is always made by the corresponding sequence like:
mPrevious[0] <-> mCurrent[0]
mPrevious[1] <-> mCurrent[1]
I need to know if at least one sequece have changed. In the example bellow, 234 changed to 230 and 146 to 149.
The sketch I have so far is:
setlocal ENABLEDELAYEDEXPANSION
#echo off
set mPrevious=229,234,235,127,58,0,131,133,146
set mCurrent=229,230,235,127,58,0,131,133,149
for /f "tokens=1,2,3,4,5,6,7,8,9 delims=," %%a IN ('echo !mPrevious!') do (
)
The number of entries (currently 9) might change in the future. But for now they are just 9.
I'm not sure what is the proper way to do it inside a batch script.
#echo off
title <nul && title ...\%~nx0
setlocal enabledelayedexpansion
set "_mPrevious=229,234,235,127,58,0,131,133,146"
set "_mCurrents=229,230,235,127,58,0,131,133,149"
echo/!_mPrevious!|find "!_mCurrents!" >nul && (
endlocal & echo\Nothing changed^!! & goto :EOF )
for %%i in (!_mPrevious!)do set /a "_i+=1+0" && call set "_mPrev_!_i!=%%~i"
for %%j in (!_mCurrents!)do set /a "_j+=1+0" && call set "_mCurr_!_j!=%%~j"
if !_i! neq !_j! endlocal & echo\Varyables have different lengths^!! & goto :EOF
for /L %%L in (1 1 !_j!)do if !_mPrev_%%~L! neq !_mCurr_%%~L! echo\!_mPrev_%%~L! updated to: !_mCurr_%%~L!
endlocal && goto :EOF
Outputs:
234 updated to: 230
146 updated to: 149
One simple way to do this only if necessary and only if both variable has same length:
Make a first comparison if the variables are the same, there was a change in the values:
echo/!_mPrevious!|find "!_mCurrents!" >nul && (
endlocal & echo\Nothing changed^!! & goto :EOF )
And a second if they continue with the same length:
if !_i! neq !_j! endlocal & echo\Variables have different lengths^!! & goto :EOF
Obs.: 1. I prefer replace [ ] to one simple _
Obs.: 2. Also, change i+= to _i+=1+0, where no need predefined set command: set i=0
The FOR token delimiters are: <SPACE> <TAB> <NBSP> , ; =
Therefore, you can put it into a FOR loop, but it would fail if the content contained * or ?.
#echo off
====SETLOCAL EnableDelayedExpansion EnableExtensions
set/a"#=cnt=0"
::Define lists
set "mPrevious=229,234,235,127,58,0,131,133,146"
set "mCurrent=229,230,235,127,58,0,131,133,149"
FOR %%P in (!mPrevious!) do (
FOR %%C in (!mCurrent!) do (
if !cnt! equ !#! echo(%%P %%C
set/a"cnt+=1"
)
set/a"cnt=0,#+=1"
)
This is an approach using some self-expanding code:
#echo off
setlocal EnableDelayedExpansion
rem // Define constants here:
set "mPrevious=229,234,235,127,58,0,131,133,146"
set "mCurrents=229,230,235,127,58,0,131,133,149"
rem // Initialise auxiliary variables and indexes:
set "nPrevious=,%mPrevious%" & set /A "i=0"
set "nCurrents=,%mCurrents%" & set /A "j=0"
rem // Convert lists to arrays using self-expanding code:
set "_=%nPrevious:,=" & set /A "i+=1" & set "nPrevious[!i!]=%"
set "_=%nCurrents:,=" & set /A "j+=1" & set "nCurrents[!j!]=%"
rem // Verify availability of arrays:
> nul 2>&1 set nPrevious[ || set /A "i=0"
> nul 2>&1 set nCurrents[ || set /A "j=0"
rem // Determine minimal and maximal count:
if %j% gtr %i% (set /A "k=i, l=j" & set "_=#") else (set /A "k=j, l=i" & set "_=")
rem // Compare corresponding elements:
for /L %%K in (1,1,%k%) do if !nPrevious[%%K]! neq !nCurrents[%%K]! (
echo [%%K]: !nPrevious[%%K]! -^> !nCurrents[%%K]!
)
rem // Return removed or added elements:
set /A "k+=1" & for /L %%K in (!k!,1,%l%) do if defined _ (
echo [%%K]: --- -^> !nCurrents[%%K]!
) else (
echo [%%K]: !nPrevious[%%K]! -^> ---
)
endlocal
Sample output, relying on the data of the question:
[2]: 234 -> 230
[9]: 146 -> 149
I'm looking to create a checklist in a console window to help users choose certain options they would like to install. This kind of output:
Please select options to install:
[x]Option 1
[ ]Option 2
>[x]Option 3
[x]Option 4
Where the user can move the cursor throughout the list and select the options.
I have a very, very vague idea of how I might do this code, testing with just two options. But if there is anyone who already has a solidified idea of how this would work and could share I would be very appreciative!
Test code for those who want to see it:
#echo off
call:main
end /b 0
:main
set /p choice= "Would you like to enable option one? (yes/no): "echo(
if %choice%==yes (
set option1=1
)
if %choice%==no (
set option1=0
)
call:mod1
set /p choice= "Would you like to enable option two? (yes/no): "echo(
if %choice%==yes (
set option2=1
)
if %choice%==no (
set option2=0
)
call:mod2
:mod1
if %option1%==1 (
echo [x] Option 1
)
if %option1%==0 (
echo [ ] Option 1
)
:mod2
if %option2%==1 (
echo [x] Option 1
)
if %option2%==0 (
echo [ ] Option 1
)
You could try this:
#echo off
setlocal EnableDelayedExpansion
for /f %%A in ('"prompt $H &echo on &for %%B in (1) do rem"') do set BS=%%A
set "getKeyMacro=powershell -noprofile "^
while (-not (37..40+13).contains($x)) {^
$x = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown').VirtualKeyCode^
}^
if ($x -eq 13) {^
'enter'^
}^
('left','up','right','down')[$x - 37]^
""
set "option1=0"
set "option2=0"
set "option3=0"
set "option4=0"
set "selected=1"
:select
cls
echo use ^<right^> arrow to continue, ^<up^> and ^<down^> to select, and ^<enter^> to toggle
FOR /L %%G IN (1,1,4) DO (
set "display=[ ]"
if !option%%G! equ 1 set "display=[x]"
if %%G equ !selected! set "display=^>!display!
echo !display! Option %%G
)
FOR /F "delims==" %%G IN ('%getKeyMacro%') DO set "key=%%G"
if "%key%"=="up" set /a "selected-=1"
if "%key%"=="down" set /a "selected+=1"
if %selected% lss 1 set "selected=1"
if %selected% gtr 4 set "selected=4"
if "%key%"=="enter" goto toggle
if "%key%"=="right" goto OK
goto select
:toggle
set /a "option%selected%+=1"
set /a "option%selected%=!option%selected%!%%2"
goto select
:OK
FOR /L %%G IN (1,1,4) DO (
if !option%%G! equ 1 (
echo %%G selected
)
)
pause
Note that this is very heavily dependent on Delayed Expansion, so you might want to read up on it here.
Second note: this needs powershell so you can use up and down arrow keys to select options, enter to toggle currently selected option, and right arrow to continue.
EDIT
Updated version, this allows you to set the display names for the options, but you need to specify the amount of options aswell:
#echo off
setlocal EnableDelayedExpansion
for /f %%A in ('"prompt $H &echo on &for %%B in (1) do rem"') do set BS=%%A
set "getKeyMacro=powershell -noprofile "^
while (-not (37..40+13).contains($x)) {^
$x = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown').VirtualKeyCode^
}^
if ($x -eq 13) {^
'enter'^
}^
('left','up','right','down')[$x - 37]^
""
set "option1=0"
set "option2=0"
set "option3=0"
set "option4=0"
set "option1name=Install thing 1"
set "option2name=Do thing 2"
set "option3name=Execute thing 3"
set "option4name=Run thing 4"
set "maxOptions=4"
set "selected=1"
:select
cls
echo use ^<right^> arrow to continue, ^<up^> and ^<down^> to select, and ^<enter^> to toggle
FOR /L %%G IN (1,1,%maxOptions%) DO (
set "display=[ ]"
if !option%%G! equ 1 set "display=[x]"
if %%G equ !selected! set "display=^>!display!
echo !display! !option%%Gname!
)
FOR /F "delims==" %%G IN ('%getKeyMacro%') DO set "key=%%G"
if "%key%"=="up" set /a "selected-=1"
if "%key%"=="down" set /a "selected+=1"
if %selected% lss 1 set "selected=1"
if %selected% gtr %maxOptions% set "selected=!%maxOptions%!"
if "%key%"=="enter" goto toggle
if "%key%"=="right" goto OK
goto select
:toggle
set /a "option%selected%+=1"
set /a "option%selected%=!option%selected%!%%2"
goto select
:OK
FOR /L %%G IN (1,1,%maxOptions%) DO (
if !option%%G! equ 1 (
echo %%G selected
)
)
pause
EDIT #2
Now uses the for loop by #Aacini to initiate the variables so this only needs to happen once, and so there is no need for a manual maxoption any more:
#echo off
setlocal EnableDelayedExpansion
set "getKeyMacro=powershell -noprofile "^
while (-not (37..40+13).contains($x)) {^
$x = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown').VirtualKeyCode^
}^
if ($x -eq 13) {^
'enter'^
}^
('left','up','right','down')[$x - 37]^
""
set "num=0"
for %%a in ("Install thing 1"
"Do thing 2"
"Execute thing 3"
"Run thing 4") do (
set /A num+=1
set "option!num!=0"
set "option!num!name=%%~a"
)
set "maxOptions=%num%"
set "selected=1"
:select
cls
echo use ^<right^> arrow to continue, ^<up^> and ^<down^> to select, and ^<enter^> to toggle
FOR /L %%G IN (1,1,%maxOptions%) DO (
set "display=[ ]"
if !option%%G! equ 1 set "display=[x]"
if %%G equ !selected! set "display=^>!display!
echo !display! !option%%Gname!
)
FOR /F "delims==" %%G IN ('%getKeyMacro%') DO set "key=%%G"
if "%key%"=="up" set /a "selected-=1"
if "%key%"=="down" set /a "selected+=1"
if %selected% lss 1 set "selected=1"
if %selected% gtr %maxOptions% set "selected=!%maxOptions%!"
if "%key%"=="enter" goto toggle
if "%key%"=="right" goto OK
goto select
:toggle
set /a "option%selected%+=1"
set /a "option%selected%=!option%selected%!%%2"
goto select
:OK
FOR /L %%G IN (1,1,%maxOptions%) DO (
if !option%%G! equ 1 (
echo %%G selected
)
)
pause
#echo off
setlocal EnableDelayedExpansion
rem Define the text for the options
set "num=0"
for %%a in ("First option"
"Second option"
"Third option"
"Fourth option") do (
set /A num+=1
set "msg[!num!]=%%~a"
set "opt[!num!]= "
)
set "digits=0123456789"
:select
(cls
echo Press digit to mark/unmark options, or X to end
echo/
for /L %%i in (1,1,%num%) do echo !digits:~%%i,1!. [!opt[%%i]!] !msg[%%i]!
)
choice /C !digits:~1,%num%!X /N > NUL
if %errorlevel% gtr %num% goto endSelect
set "sel=%errorlevel%"
if "!opt[%sel%]!" equ "X" (set "opt[%sel%]= ") else set "opt[%sel%]=X"
goto select
:endSelect
echo/
echo/
for /L %%i in (1,1,%num%) do (
if "!opt[%%i]!" equ "X" (
echo %%i selected
)
)
I have to make a script that has to calculate the mask and the net, so I'm trying a script with for but it can not convert the IP to binary. I think I'm not using the variables right.
Any ideas?
#echo off
setlocal enabledelayedexpansion
set var=%1
set /p var=Introduce la ip:
for /F "tokens=1 delims=." %%a in ("%var%") do (
echo %%a
set "vara=%%a"
:binario
set bin=2
set /a resto=%vara%%%bin%
set /a a=%vara%/%bin%
set resultado=%resto%%resultado%
if %vara% GTR 0 (goto binario)
echo %resultado%
goto siguiente
)
:siguiente
for /F "tokens=2 delims=." %%b in ("%var%") do (
echo %%b
)
for /F "tokens=3 delims=." %%c in ("%var%") do (
echo %%c
)
for /F "tokens=4 delims=." %%d in ("%var%") do (
echo %%d
)
goto fin
:vacio
echo Error!
goto fin
:fin
pause
You've got a few minor problems that I see. You set var=%1 but you never check to see whether %1 was supplied before doing set /p var=Enter an IP:. You never call or goto :vacio. As I commented above, modulos within batch scripts need to be written as %% to prevent evaluation as variable chararacters. You don't need % in var names in set /a commands, and you can combine multiple set /a statements with a comma. So instead of
set /a resto=%vara%%%bin%
set /a a=%vara%/%bin%
(which is wrong anyway -- I'll get to that in a minute), I suggest this would be more understandable and maintainable:
set /a resto = vara %% bin, numero = vara / bin
The biggest problem is that you appear to be trying to modify %%a. Don't do that.
If I were you, I would move the decimal to binary conversion to a subroutine, and call it for each octet. Try this:
#echo off
setlocal enabledelayedexpansion
set IP=%1
if "%IP%"=="" set /p "IP=Introduce la ip: "
set idx=0
for %%a in (%IP:.= %) do (
if %%a lss 0 goto vacio
if %%a gtr 255 goto vacio
if !idx! gtr 3 goto vacio
set /P "=%%a = "<NUL
call :dec2bin bin[!idx!] %%a
set /a idx += 1
)
echo %bin[0]%.%bin[1]%.%bin[2]%.%bin[3]%
goto fin
:dec2bin <var_para_definir> <numero>
setlocal enabledelayedexpansion
set numero=%~2
set bin=
for /L %%I in (1,1,8) do (
set /a bit = numero %% 2, numero /= 2
set bin=!bit!!bin!
)
echo %bin%
endlocal & set "%~1=%bin%"
goto :EOF
:vacio
echo Error!
goto fin
:fin
pause
For more information about using call as a function that returns a value, see this page.
I have been trying for days and can seem to get this to work. I found an example but it uses a (CryEcho) which will not work. I just wanted to add this to let the user know something is going on while im pinging IP addresses. I did find some code on here but it was confusing to me since im just starting to mess around with batch files for fun.
Anyway, I wanted to have something that used something like the example below but with text like (Waiting...[spinner]). Thanks!
#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
AND I found this code as well:
#echo off
rem Example showing how to use CryEcho to produce a spinning wheel to show activity.
CryEcho Working ...
call :DoSomeWork
call :SpinAlive
call :DoSomeWork
call :SpinAlive
call :DoSomeWork
call :SpinAlive
call :DoSomeWork
call :SpinAlive
call :DoSomeWork
call :SpinAlive
call :DoSomeWork
call :SpinAlive
call :DoSomeWork
call :SpinAlive
call :DoSomeWork
call :SpinAlive
call :DoSomeWork
cryecho \s\nFinished.
goto :eof
:DoSomeWork
ping -n 1 localhost > nul
goto :eof
:SpinAlive
if "%Spinner%" == "2" (cryecho \\\b)
if "%Spinner%" == "3" (cryecho -q "|"\b)
if "%Spinner%" == "4" (cryecho /\b set Spinner=0) else (cryecho -\b set Spinner=1)
set /A Spinner=%Spinner%+1
goto :eof
The main trick is here to move the cursor back on the same line.
This can be done with a carriage return or a backspace characters.
#echo off
setlocal EnableDelayedExpansion
for /f %%a in ('copy /Z "%~dpf0" nul') do set "CR=%%a"
FOR /L %%n in (1,1,10) DO (
call :spinner
ping localhost -n 2 > nul
)
exit /b
:spinner
set /a "spinner=(spinner + 1) %% 4"
set "spinChars=\|/-"
<nul set /p ".=Waiting !spinChars:~%spinner%,1!!CR!"
exit /b
The <CR> character is created from the output of copy /z.
The output is done by set /p, as this omits the output of CR/LF at the end.
The !CR! is output each time to force the cursor to move back to the first column.
But as Win7 and Vista removes all whitespaces and also CR from the leading output of set /p, it's placed at the end.
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
CALL :BACKSPACE $BS
SET /A FULL_COUNT=75
SET /A MAX_COUNT=160
SET /A Spin_Delay=60
SET "_MSG=Process running..."
SET /A CTR=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 /A FULL_COUNT=%MAX_COUNT%
<nul SET/P="%_MSG%*"
SET "SPINNER=³/Ä\"
FOR /L %%A IN (1,1,%FULL_COUNT%) DO (
CALL :DELAY %SPIN_DELAY%
<nul CALL SET/P="%$BS%%%SPINNER:~!CTR!,1%%"
SET /A CTR=%%A %% 4
)
<nul SET/P="%$BS%*"
ENDLOCAL & EXIT /B %CTR%
:BackSpace
setlocal
for /f %%a in ('"prompt $H&for %%b in (1) do rem"') do set "BS=%%a"
endlocal&call set %~1=%BS%&exit /b 0
:Delay msec
setlocal
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%