Compare numerals in batch - batch-file

Posting part of the code which am looking for a workaround
if 09 LSS 9 (ECHO YES) ELSE (ECHO NO)
This command always echo's 'Yes' as it considers 09 to be less than 9. Any alternative for this command?
EDIT:
Thanks but the Modulo part is not working in the command i am trying to insert in.
Have a file test.txt which contains "1234 09" below is my command
set actualdate=9
for /f "usebackq Tokens=1,2,3" %%d in (test.txt) do (SET /a x=1000%%e %% 1000 & if %x% LSS %ActualDate% ECHO %%d >> test2.txt)

The problem with your code snippet is the syntax and also the percent expansion.
You can use & for multiple commands in one line (not the pipe |) or split them into multiple lines.
You can't access the variable x with percent expansion inside of a block, but delayed expansion works there
setlocal EnableDelayedExpansion
set actualdate=9
for /f "usebackq Tokens=1,2,3" %%d in (test.txt) do (
SET /a x=1000%%e %% 1000
if !x! LSS %ActualDate% ECHO %%d >> test2.txt
)

If you can put your numbers into variables, you can strip off the leading zero using modulo.
Try this sample:
#ECHO OFF
SET a=09
SET b=9
SET /a x=1000%a% %% 1000
ECHO %x%
SET /a y=1000%b% %% 1000
ECHO %y%
if %x% LSS %y% (ECHO YES) ELSE (ECHO NO)
PAUSE
If you try to do SET /a a=09, you'll get the following error:
Invalid number. Numeric constants are either decimal (17), hexadecimal (0x11) or octal (021).

Related

How to make a random chance "function" in Batch

I'm making a small little game I want a random chance to get certain items (e.g. if the random number is greater than 10 but less than 15 then you will get a certain item). Here's what I've already tried which resulted in a crash.
set /a chance= %random% %%30+1
if %chance% gtr 10 && lss 30 (
set /a %nails%+1
echo You got nails! %chance%
)
This piece right here was just a test, but should give you an idea of what I am going for. This is really the only way I can think of doing it. If you could help, please do! :)
I see a number of problems in that code:
set /a chance= %random% %%30+1
if %chance% gtr 10 && lss 30 (
set /a %nails%+1
echo You got nails! %chance%
)
Going through them:
The if statement is not valid, && is the "execute next command if previous command worked" conjunction, not a general "and" operator. To do what you want would be:if %chance% gtr 10 if %chance% lss 30.See here for a way to do and and or in cmd language.
The command set /a %nails%+1 does not actually change nails in any way, it just evaluates an expression and throws it away. You need an assignment to assign a value, and you don't need the variable markers in this case:set /a "nails += 1".
If you're using delayedexpansion to print out nails (and you should be), you need a ! both before and after the variable name:echo You got !nails! %chance%.
As an aside, you'll probably notice I have a penchant for quoting my set /a expressions and spacing them nicely - I find this aids readability.
That will fix some specific problems but, to be honest, you're probably better off making a generic function that can give you a yes/no answer for some probability of an event happening. That way, you can reuse it anywhere you need it.
You can use a function like chance, shown below in a complete program, to decide whether something should happen based on a percentage:
#echo off
goto :main
:chance
setlocal enableextensions enabledelayedexpansion
set retcode=1==0
set /a "value = %random% %% 100"
rem echo %value% rem uncomment for debugging
if %value% lss %2 set retcode=1==1
endlocal && set %1=%retcode%
goto :eof
:main
call :chance result 50
echo %result%
It should be called with both a variable name to put the result into, and the percentage level you want to use. For example, if you wanted to set a variable hasdied based on a 5% chance, you would call it with:
call :chance hasdied 5
if %hasdied% goto :handlebeingdead
The function contains a number of features which probably bear explanation:
The setlocal command ensures that no variables escape the scope of this function (but see below), useful for proper encapsulation.
The value variable is set to some random value between 0 and 99 inclusive. It's not perfectly distributed since %random% will give you a value up to 32767 so will be slightly skewed toward numbers less than 68. Said skew is probably not enough to concern yourself with.
This value is then compared with the threshold you provided (the second argument) to decide the return value true or false.
The return value is rather sneaky in that it gives you an expression that you can put into an if statement without having to do an explicit comparison like:if %hasdied%==1By returning such an equality comparison directly, you can just use the return value as if it was boolean.
The endlocal then cleans up any variable changes that have been made in this function, including the return code. However, the fact that the substitutions on this line take place before any of it is executed means that the set part of it will already have the correct value of retcode substituted before the endlocal cleans it up. This is a way to have specific variables "escape" the scope bounded by setlocal/endlocal. The retcode value is therefor placed in the parameter whose name you provided as the first argument.
The set %1= part of that command is a way to allow you to specify what variable should receive the value in the call itself, akin to myvar = function(). That stops you from having to allocate a hard-coded variable name to each function and then assign it to another variable after the call.
And, of course, the goto :eof is simply a return instruction.
I'm pretty sure the && does not exist in batch. Nested if statements work:
set /a chance= %random% %%30+1
echo %chance%
IF %chance% GTR 10 (IF %chance% LSS 15 (
echo You got nails! %chance%
))
You cannot use && like that. You need to run the if statement twice to match both gtr and lss you can put them one after the other:
#echo off
set /a chance=%random% %%30+1
if %chance% gtr 10 if %chance% lss 30 (
set /a nails+=1
echo You got nails! %chance%
)
Also note the correct way of increasing a variable set /a nails+=1
the if condition approach works and all, but is somewhat clunky if your going to be scripting in many loot situations. it is by far easier to use an array setup with a macro that can access ranges within the array to allow you to simply and easily script loot boxes that roll different items by using substring modification to change the index of the array the random number can access. a demonstration:
#Echo off
:new
::: -------------------------------------------------------------------|| MACRO DEFINITIONS
Setlocal DisableDelayedExpansion
(Set \n=^^^
%=DNR=%
)
rem ********************* Display any existing character names for continuation or deletion of characters
If Exist "%TEMP%\%~n0_*_save.bat" (Echo/Your Characters:&Echo/&(For /F "Delims=" %%G in ('Dir "%TEMP%\%~n0_*_save.bat" /B')Do For /F "Tokens=2 Delims=_" %%o in ("%%~nG") Do < Nul Set /P "=[%%o] ")&Echo/)
:character
Set /P "Name=Name: "
If Exist "%TEMP%\%~n0_%Name%_save.bat" (Echo/[C]ontinue / [D]elete?&For /F "Delims=" %%O in ('Choice /N /C:cd')Do If /I "%%O"=="C" (Goto :playon)Else (Del /P "%TEMP%\%~n0_%Name%_save.bat" & Goto :character))
If "%Name%"=="" Goto :character
:playon
rem *** Inventory Macro. Displays all elements for the given group and their current values.
rem ::: Usage: %INV:#=$varname[%
Set "INV=Echo/&(For /F "Tokens=2 Delims==" %%i in ('Set #') Do (Set "VN=%%i"&^< Nul Set /P"=[!VN:$=!:!%%i!] "))&Echo/"
rem *** Autosave macro. Can be incorperated into other macro's
rem ::: Usage: %Save%
Set SAVE=(For /F "Tokens=1 Delims==" %%i in ('Set $') Do (If not "!%%i!"=="" Echo/Set "%%i=!%%i!"))^>"%TEMP%\%~n0_!name!_save.bat"
rem *** Location Display Macro with autosave macro included
rem ::: Usage: %Loc:#=LocationLABEL%
Set "Loc=(Set "$Loc=#"&Title !$Loc:_= !)&%Save%"
rem *** Loot box Macro to generate random loot from specified range of an indexed array
rem *** !random! %%4 + Index# will access an index range between the index # and 4 above the index number.
rem ::: Usage: %Loot:#=index#%
Set "LOOT=(For /F "UsebackQ Delims=" %%i in (`"Set /A i#=!Random! %%4 + #"`) Do For /F "UsebackQ Delims=" %%v in (`"Set /A v#=!Random! %%3 + 1"`) Do (Set "VN=!$Loot[%%i]:$=!"&Echo/You got %%v !VN!&Set /A "!$Loot[%%i]!+=%%v")) 2> Nul & %SAVE%"
rem *** the below macros /I /V and /P are not used in this example. - They are an optional method for defining
rem *** variables prefixed with $ that automatically saves them for reloading
rem ::: usage: %/I:V=Varname%Input Prompt String:
Set "/I=For %%n in (1 2)Do If %%n==2 (Set /P "$V=!$PromptStr:$=!: "&%Save%)Else Set $PromptStr="
rem ::: usage: %/P:V=Varname%VariableValue
Set "/V=For %%n in (1 2)Do If %%n==2 (Set "$V=!str!"&%Save%)Else Set str="
rem ::: usage: %/A:V=Varname%=Equation
Set "/A=For %%n in (1 2)Do If %%n==2 (Set /A "$V!sum!"&%Save%)Else Set sum="
rem *** Wait prompt Macro
rem ::: usage: %Wait:#=Integer value for time in seconds%Wait Prompt String
Set "Wait=For %%n in (1 2)Do If %%n==2 (Timeout # /Nobreak > Nul & (Pause | Echo/!Output!) 2> Nul )Else Set Output="
rem *** Array definition macro. Asigns the element names to an indexed Groupname (Array), With each element being assigned an initial 0 value
Rem ::: Usage: %DefArray%{VarGroupName}{Element names as list}
Set DefArray=For %%n in (1 2) Do if %%n==2 (%\n%
Set "i#=0"%\n%
For /F "Tokens=1,2 Delims={}" %%G in ("!List!") Do (%\n%
For %%i in (%%~H) Do (%\n%
Set "$%%~G[!i#!]=$%%i"%\n%
Set "$%%i=0"%\n%
Set /A i#+=1 ^> Nul%\n%
)%\n%
)%\n%
) Else Set List=
Set Menu=CLS^&Set "Copt="^&For %%n in (1 2) Do if %%n==2 (%\n%
Echo/[E]xit%\n%
For %%G in (!OPTS!)Do (%\n%
Set "opt=#%%~G"%\n%
Set "opt=!opt:_= !"^&Set "Opt=!Opt:~,-1!"%\n%
Set "Copt=!Copt!%%~G"%\n%
Echo/!Opt! [%%~G]%\n%
)%\n%
(For /F "Delims=" %%O in ('Choice /N /C !Copt!E')Do If "%%O"=="E" (Endlocal^&Endlocal^&Set "Name="^&Goto :New) Else (CLS^&Goto :#%%O))%\n%
) Else Set OPTS=
::: -------------------------------------------------------------------|| END MACRO DEFINITIONS
::: -------------------------------------------------------------------|| Example Script
REM // required to be enabled PRIOR to macro Use, AFTER definition.
Setlocal EnableDelayedExpansion
%DefArray%{Loot}{Wood Nails Ore Leather Gold Silver Bronze Jade}
IF Exist "%TEMP%\%~n0_!name!_save.bat" (
Call "%TEMP%\%~n0_!name!_save.bat"
Goto :!$Loc!
)
:Menu
%Loc:#=Menu%
%Menu:#=Loot_Box_% "1" "2"
Goto :Menu
:Loot_Box_1
%Loc:#=Loot_Box_1%
%Loot:#=0%
%INV:#=$Loot[%
%Wait:#=1%
Goto :Menu
:Loot_Box_2
%Loc:#=Loot_Box_2%
%Loot:#=4%
%INV:#=$Loot[%
%Wait:#=1%Demo wait prompt
Goto :Menu

batchfile verify input formating ( length and numbers only)

I'm trying to make sure the user of the batchfile is inputing a 6 digit numbers only.
No more no less and only numbers.
I found the code bellow in this thread but can't figure how to modify it for my need.
Reference code
:Prompt
SET /P "UserInput=Please Enter Version as X.X.X.X: "
FOR /F "TOKENS=1-4 DELIMS=." %%i IN ("%UserInput%") DO (
SET /A n1=1*%%i
SET /A n2=1*%%j
SET /A n3=1*%%k
SET /A n4=1*%%l
)
IF NOT "%UserInput%" == "%n1%.%n2%.%n3%.%n4%" GOTO :Prompt
ECHO %UserInput%
I thought that modifying the code like so would do the trick but it does not
My modification to the reference code
:Prompt
SET /P "UserInput=Please Enter Version as XXXXXX: "
FOR /F "TOKENS=1-6" %%i IN ("%UserInput%") DO (
SET /A n1=1*%%i
SET /A n2=1*%%j
SET /A n3=1*%%k
SET /A n4=1*%%l
SET /A n4=1*%%m
SET /A n4=1*%%n
)
IF NOT "%UserInput%" == "%n1%%n2%%n3%%n4%%n5%%n6%" GOTO :Prompt
ECHO %UserInput%
What i'm I doing wrong and i'm I on the right track?
Thank you and have a nice day!
You could avoid labels or verfication by simply restricting the input to allowed characters and length, then just append any 'fixed' characters to the string.
#Echo off &Setlocal EnableDelayedExpansion
Set nVar=
Echo/Enter 6 Digit Integer:&(For /L %%# in (1 1 6)Do For /F "Delims=" %%G in ('Choice /N /C 0123456789')Do (<Nul Set /P"=%%G"&Set "nvar=!nVar!%%G"))&Echo/
Echo/Var [!nVar!] Entered
Endlocal
If you need numerical strings of varying lengths, then you can turn the above into a macro and use substring modification to supply the number of digits required.
#Echo off & Setlocal EnableDelayedExpansion
Set "Input=(Set "nVar="&Echo/Enter # Digit Integer:&(For /L %%. in (1 1 #)Do For /F "Delims=" %%G in ('Choice /N /C 0123456789')Do (<Nul Set /P"=%%G"&Set "nvar=^^!nVar^^!%%G"))&Echo/)"
%Input:#=6% & Echo/Var [!nVar!] Entered
Endlocal
You could do the following:
:INPUT
rem // Clear variable to not use previous value if user just presses {Enter}:
set "UserInput="
rem // Prompt for user input:
set /P UserInput="Please enter version as XXXXXX: "
rem // Evaluate user input:
cmd /V /C echo(!UserInput!| > nul findstr "^[0-9][0-9][0-9][0-9][0-9][0-9]$" || goto :INPUT
echo Entered version is %UserInput%.
To avoid a few other characters, like 2 and 3 (available on German keyboards), or also 1, depending on the current code page, to be unintentionally accepted, change each expression [0-9] to [0123456789].

How to store the split value in variable to subtract from another variable in batch script [duplicate]

This question already has answers here:
Variables are not behaving as expected
(1 answer)
Example of delayed expansion in batch file
(5 answers)
Closed 2 years ago.
I have few zip files in a folder with a number in it's name with underscore like C:\codedeploy\uat-prod\xxxx_123.zip. I would like to iterate through all files and get the number in file name into a variable(fileNumber) to substract it from a another variable(buildNumber)(this is integer value which I am loading from a text file).
After first split I am able to get 123.zip(in %%a), So, for getting number from this, I split that again(got this into %%i). Then I tried assigning these values to variable fileNumber, buildNumber and result. I checked it whether these variables are getting assigned values by writing them into a test.txt file with comma separated. but all the variable values are empty. After these values calculated properly I would like to delete the file if it satisfies the this condition if %result% GEQ %limit%.
set /p Build=<release_version.txt
Setlocal EnableDelayedExpansion
set /A result=0
for %%f in (C:\codedeploy\uat-prod\*.zip) do (
echo "fullname: %%f ">>"C:\codedeploy\uat-prod\test.txt"
for /f "tokens=2 delims=_" %%a in ("%%f") do (
set limit=7
echo "FileNum: %%a">>"C:\codedeploy\uat-prod\test.txt"
for /f "tokens=1,2 delims=." %%i in ("%%a") do (
echo "Num: %%i">>"C:\codedeploy\uat-prod\test.txt"
set /A fileNumber=%%i
set /A buildNumber=%Build%
set /a result=buildNumber-fileNumber
echo "fileNumber: %fileNumber%, buildNumber: %buildNumber%, finla: %result%">>"C:\codedeploy\uat-prod\test.txt"
REM set /a result=%Build%-%%i
REM echo "value is=%result%"
REM if %result% GEQ %limit% (Del %%f)
REM if %result% GEQ %limit% (Del "%%f")
rem if %Build%-%%i GEQ %limit% (Del /S /Q "%%f")
)
)
)
I have been scratching my head to achieve this. So, any help on this would be appreciated.
Thanks in advance.
I may not quite have understood what you were trying to achieve, but this looks like it should work the same but more efficiently, (and obviously uses the appropriate !'s for the delayed variable).
Set /P "Build=" 0< "release_version.txt"
Set "limit=7"
Set "result=0"
(
For %%G In ("C:\codedeploy\uat-prod\*_*.zip") Do (
Echo "fullname: %%G"
For /F "EOL=: Tokens=2 Delims=_" %%H In ("%%~nG") Do (
Echo "FileNum: %%H%%xG"
Echo "Num: %%H"
SetLocal EnableDelayedExpansion
Set /A result=Build - %%H
Echo "fileNumber: %%H, buildNumber: %Build%, final: !result!"
Rem If !result! GEq %limit% Del /A /F "%%G"
EndLocal
)
)
) 1> "C:\codedeploy\uat-prod\test.txt"

Xor a string in a bat file?

In short I want to give my friend a bat file which does the below (untested)
echo Your mother is so fat
pause
echo the recursive function computing her mass causes a stack overflow
I might copy/paste him the bat file so I don't want the punch line to be ruined. How can I hide the text? I was thinking I can store the string in a variable and before I echo it I should XOR each letter with 32. But I have no idea how to take a string, XOR each letter than echo it to display the joke. How might I hide the text? I could also BASE64 encode/decode it but IDK how to do that either if I am only using a bat file
1) Here's one way to hide the text using mshta as a command line tool (with ascii codes in this case) :
#echo off
mshta vbscript:execute("CreateObject(""Scripting.FileSystemObject"").GetStandardStream(1).Write(Chr(89) & Chr(111)& Chr(117) & Chr(114) & Chr(32) & Chr(109) & Chr(97) & Chr(109) & Chr(97) & Chr(32) ):Close")|more
2) You can use CERTUTIL to encode/decode base64/hex files but it requires a temporary file that can be silently deleted (more info ):
echo 796f7572206d616d6120697320736f20666174>"%temp%\fat.hex"
certutil -decodehex "%temp%\fat.hex" "%temp%\fat.txt" >nul 2>&1
type "%temp%\fat.txt"
del /q /f "%temp%\fat.txt"
3) Dbenham's hex print function
#echo off
setlocal
::Define a Linefeed variable
set LF=^
::above 2 blank lines are critical - do not remove.
::Create a string variable with encoded TABs
call :hexprint "0x790x6f0x750x720x200x6d0x610x6d0x610x200x690x730x200x730x6f0x200x660x610x74" var
echo %var%
exit /b
:hexPrint string [rtnVar]
for /f eol^=^%LF%%LF%^ delims^= %%A in (
'forfiles /p "%~dp0." /m "%~nx0" /c "cmd /c echo(%~1"'
) do if "%~2" neq "" (set %~2=%%A) else echo(%%A
exit /b
4) carlos' genCar function that uses MAKECAB:
#echo off
setlocal
break>fat.txt
for %%# in (121 111 117 114 32 109 97 109 97 32 105 115 32 115 111 32 102 97 116) do (
call :genChar %%#
type %%#.chr>>fat.txt
del /q /f %%#.chr >nul 2>&1
)
type fat.txt
del /q /f fat.txt
goto :eof
:genChar
setlocal
set "USAGE=echo:Usage: Supply an integer 0-255& goto :EOF"
if "%~1" equ "" %USAGE%
set /a "val=%~1" 2>nul
if "%~1" neq "%val%" %USAGE%
if %~1 lss 0 %USAGE%
if %~1 gtr 255 %USAGE%
set tempfile=%~1.tmp
set "options=/d compress=off /d reserveperdatablocksize=26"
if %~1 neq 26 (type nul >"%tempfile%"
makecab %options% /d reserveperfoldersize=%~1 "%tempfile%" %~1.chr >nul
type %~1.chr | (
(for /l %%N in (1 1 38) do pause)>nul&findstr "^">"%tempfile%")
>nul copy /y "%tempfile%" /a %~1.chr /b
del "%tempfile%"
) else (copy /y nul + nul /a 26.chr /a >nul)
endlocal
for more cryptic script you can combine hem.Only MSHTA and MAKECAB solutions will work on every windows machine. FORFILES and CERTUTIL are default form Vista and above I think.It is possible to create a few more examples ...
This is a subject near and dear to my heart because I did something similar in my implementation of the classic Colossal Cave Adventure game as a Windows batch file.
Within the game script I selectively encrypt display text, variable names, and comments. The code to decode the encrypted text is embedded directly within the same script! I write the source code for the game normally, and use braces to denote what portion is to be encrypted. A function within the game is able to generated the encrypted form of itself!
I used a simple symmetric rotation cipher, so really it is more obfuscation than encryption. But that is all that is needed for both the game, and your situation.
I've extracted a simplified version of the routines and provide them below.
The first script is a standalone script that selectively encrypts text within a source file and writes the result to stdout. Simply redirect the output to a new file to get the encrypted version of the file.
selectiveROT13.bat
#echo off
:selectiveROT13 InFile
::
:: Selectively applies the simple "rotate alphabet 13 places" cipher
:: to the contents of file InFile. Only text between curly braces
:: is affected. The affected content can span multiple lines.
::
:: Writes the results to stdout.
:: Percent completion is continuously written to stderr.
::
setlocal enableDelayedExpansion
set "upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ"
set "lower=abcdefghijklmnopqrstuvwxyz"
for /l %%A in (0 1 25) do (
set /a "B=(%%A+13)%%26"
for /f %%B in ("!B!") do (
set "upper!upper:~%%A,1!=!upper:~%%B,1!"
set "lower!lower:~%%A,1!=!lower:~%%B,1!"
)
)
setlocal disableDelayedExpansion
>&2 cls
set "active="
for /f %%N in ('type %1^|find /c /v ""') do set /a "lnCnt=%%N, pct=-1"
for /f "skip=2 tokens=1,* delims=[]" %%a in ('find /v /n "" %1') do (
set "ln=%%b"
setlocal enableDelayedExpansion
set "str=A!ln!"
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 len-=1
set rtn=
for /l %%n in (0,1,!len!) do (
set "c=!ln:~%%n,1!"
if "!c!" equ "{" set "active=1"
if "!c!" equ "}" set "active="
if defined active if defined upper!c! for /f %%c in ("!c!") do (
if "!upper:%%c=%%c!" equ "!upper!" (
set "c=!upper%%c!"
) else (
set "c=!lower%%c!"
)
)
set "rtn=!rtn!!c!"
)
echo(!rtn!
for %%A in ("!active!") do (
endlocal
set "active=%%~A"
)
)
exit /b 0
Below is your joke program with a simplified version of the code to decode encrypted text. My original code worked with string variables, but this version works with string literals. The source script is written normally, without encryption. Braces indicate which code is to be encrypted. Besides your joke, I've included documentation and examples to demonstrate some of the features.
joke_src.bat
#echo off
setlocal enableDelayedExpansion
call :init
:: Disable delayed expansion to protect ! within string literals
setlocal disableDelayedExpansion
:: Curly braces are used to denote text that should be encrypted.
:: Encryption can span multiple lines
:: {
:::Line1
:::Line2
:::Line3
:: }
:: I defined a simple SHOW macro that expands to CALL :SHOW
:: Use the %show% macro to display encrypted text.
:: The braces can be hidden by using the undefined %{% & %}% variables
%show% %{%"Quote literals ("") must be doubled ("""") in the source"%}%
:: Here I use a FOR loop to show all encrypted lines within this script
:: that begin with :::
echo(
for /f "delims=: tokens=*" %%A in ('findstr /b ":::" "%~f0"') do %show% "%%A"
echo(
echo And now it is time for a little joke.
echo(
echo Your mother is so fat...
pause
%show% %{%"the recursive function computing her mass causes a stack overflow!"%}%
exit /b
:show Str
::{
:: Applies the simple "rotate alphabet 13 places" cipher to string Str
:: and writes the result to stdout. Consecutive quotes ("") are converted
:: into a single quote (").
::}
setlocal disableDelayedExpansion
set "str=%~1"
setlocal enableDelayedExpansion
set "str=!str:""="!^"
if defined {obfuscated} (
set "len=0"
set "str2=.!str!"
for /L %%A in (12,-1,0) do (
set /a "len|=1<<%%A"
for %%B in (!len!) do if "!str2:~%%B,1!"=="" set /a "len&=~1<<%%A"
)
set /a len-=1
set rtn=
for /l %%n in (0,1,!len!) do (
set "c=!str:~%%n,1!"
if defined {upper}!c! for /f %%c in ("!c!") do (
if "!{upper}:%%c=%%c!" equ "!{upper}!" (
set "c=!{upper}%%c!"
) else (
set "c=!{lower}%%c!"
)
)
set "rtn=!rtn!!c!"
)
) else set "rtn=!str!"
echo(!rtn!
exit /b 0
:init
set "}="
set "{="}
set "{upper}=ABCDEFGHIJKLMNOPQRSTUVWXYZ"
set "{lower}=abcdefghijklmnopqrstuvwxyz"
for /l %%A in (0 1 25) do (
set /a "B=(%%A+13)%%26"
for /f %%B in ("!B!") do (
set "{upper}!{upper}:~%%A,1!=!{upper}:~%%B,1!"
set "{lower}!{lower}:~%%A,1!=!{lower}:~%%B,1!"
)
)
set "{obfuscated}="
set "{obfuscationTest}={A}"
if "!{obfuscationTest}:A=!" equ "!{obfuscationTest}!" set {obfuscated}=1
set "show=call :show"
exit /b
The following command will generate the encrypted version of the script:
selectiveROT13 joke_src.bat >joke.bat
Below is the encrypted form. This is what you would send to your friend. (Without the extra documentation and examples of course)
joke.bat
#echo off
setlocal enableDelayedExpansion
call :init
:: Disable delayed expansion to protect ! within string literals
setlocal disableDelayedExpansion
:: Curly braces are used to denote text that should be encrypted.
:: Encryption can span multiple lines
:: {
:::Yvar1
:::Yvar2
:::Yvar3
:: }
:: I defined a simple SHOW macro that expands to CALL :SHOW
:: Use the %show% macro to display encrypted text.
:: The braces can be hidden by using the undefined %{% & %}% variables
%show% %{%"Dhbgr yvgrenyf ("") zhfg or qbhoyrq ("""") va gur fbhepr"%}%
:: Here I use a FOR loop to show all encrypted lines within this script
:: that begin with :::
echo(
for /f "delims=: tokens=*" %%A in ('findstr /b ":::" "%~f0"') do %show% "%%A"
echo(
echo And now it is time for a little joke.
echo(
echo Your mother is so fat...
pause
%show% %{%"gur erphefvir shapgvba pbzchgvat ure znff pnhfrf n fgnpx biresybj!"%}%
exit /b
:show Str
::{
:: Nccyvrf gur fvzcyr "ebgngr nycunorg 13 cynprf" pvcure gb fgevat Fge
:: naq jevgrf gur erfhyg gb fgqbhg. Pbafrphgvir dhbgrf ("") ner pbairegrq
:: vagb n fvatyr dhbgr (").
::}
setlocal disableDelayedExpansion
set "str=%~1"
setlocal enableDelayedExpansion
set "str=!str:""="!^"
if defined {boshfpngrq} (
set "len=0"
set "str2=.!str!"
for /L %%A in (12,-1,0) do (
set /a "len|=1<<%%A"
for %%B in (!len!) do if "!str2:~%%B,1!"=="" set /a "len&=~1<<%%A"
)
set /a len-=1
set rtn=
for /l %%n in (0,1,!len!) do (
set "c=!str:~%%n,1!"
if defined {hccre}!c! for /f %%c in ("!c!") do (
if "!{hccre}:%%c=%%c!" equ "!{hccre}!" (
set "c=!{hccre}%%c!"
) else (
set "c=!{ybjre}%%c!"
)
)
set "rtn=!rtn!!c!"
)
) else set "rtn=!str!"
echo(!rtn!
exit /b 0
:init
set "}="
set "{="}
set "{hccre}=ABCDEFGHIJKLMNOPQRSTUVWXYZ"
set "{ybjre}=abcdefghijklmnopqrstuvwxyz"
for /l %%A in (0 1 25) do (
set /a "B=(%%A+13)%%26"
for /f %%B in ("!B!") do (
set "{hccre}!{hccre}:~%%A,1!=!{hccre}:~%%B,1!"
set "{ybjre}!{ybjre}:~%%A,1!=!{ybjre}:~%%B,1!"
)
)
set "{boshfpngrq}="
set "{boshfpngvbaGrfg}={N}"
if "!{boshfpngvbaGrfg}:A=!" equ "!{boshfpngvbaGrfg}!" set {boshfpngrq}=1
set "show=call :show"
exit /b
The beauty of this system is that both joke.bat and joke_src.bat generate the exact same output:
Quote literals (") must be doubled ("") in the source
Line1
Line2
Line3
And now it is time for a little joke.
Your mother is so fat...
Press any key to continue . . .
the recursive function computing her mass causes a stack overflow!
Another nice feature is that selectiveROT13.bat can be applied to joke.bat to regenerate the original un-encrypted source.
This code creates a base64 encoded file:
#echo off
set "var=the recursive function computing her mass causes a stack overflow"
>file.tmp echo %var%
certutil -f -encode file.tmp file.tmp2 >nul
echo file.tmp2|find /v "-----" >file.txt
del file.tmp?
pause
and you can use the file like so (adding echo at the start of each line of the encoded file):
#echo off
cls
echo Your mother is so fat
pause
(
echo dGhlIHJlY3Vyc2l2ZSBmdW5jdGlvbiBjb21wdXRpbmcgaGVyIG1hc3MgY2F1c2Vz
echo IGEgc3RhY2sgb3ZlcmZsb3cNCg==
)>file.tmp
certutil -f -decode file.tmp file.txt >nul
timeout /t 2 /nobreak >nul
type file.txt
timeout /t 5 /nobreak >nul
I think you can just replace some chars with others in pure BAT without any temporary files using following string replacing script.
%str:old_char=new_char%
For example, I have defined some encoding and decoding functions. The codes are attached here, and it will print what you want.
#echo off
set str1=Y urke ohtrkmsks kfao
set str2=ohtkrtcursmvtkfuncom nkc epuomngkhtrkeasskcaustskaksoacik vtrfl w
call :decode "%str1%"
call :decode "%str2%"
pause
goto :eof
:decode
set "str=%~1"
set str=%str: =#%
set str=%str:k= %
set str=%str:i=k%
set str=%str:m=i%
set str=%str:e=m%
set str=%str:t=e%
set str=%str:o=t%
set str=%str:#=o%
echo %str%
goto :eof
I also attached the encoding script below.
#echo off
set str1=Your mother is so fat
set str2=the recursive function computing her mass causes a stack overflow
call :encode "%str1%"
call :encode "%str2%"
pause
goto :eof
:encode
set "str=%~1"
set str=%str:o=#%
set str=%str:t=o%
set str=%str:e=t%
set str=%str:m=e%
set str=%str:i=m%
set str=%str:k=i%
set str=%str: =k%
set str=%str:#= %
echo %str%
goto :eof

what is the best way for this condition

can someone please tell me how can I make a batch file the inputs 5 numbers and checks for each number if its even ir odd? i dont know what i did wrong about the module part:
#echo off
for /l %%i IN (1,1,5) DO (
set /p num1=
set /a "mod=%num1% %% 2"
echo mod=%mod%
if mod EQU 0 (echo EVEN!)else echo ODD!
echo.
)
echo 5 numbers were inputed.
echo.
pause
and another question: Can I not declare the num1 variable and check if its even inside the if (having a mathematical expression inside the if and not only a simple comparison)?
thanks :)
You cannot do mathematical computations within an IF statement.
Here are some problems with your code:
Normal expansion occurs when a statement is parsed, and all code within your FOR loop is parsed in one pass. So %mod% expands to a constant value - the value that existed before the FOR loop begain (or empty string if mod was not defined).
Variables must be expanded if you want to use them in an IF statement.
Not a bug - but numeric variables do not need to be expanded to use them in a SET /A statement.
Here is one solution - have the loop call a subroutine that gets reparsed each iteration:
#echo off
setlocal
for /l %%i in (1,1,5) do call :test
echo 5 numbers were inputed.
echo(
pause
exit /b
:test
set /p "num1=Enter a number: "
set /a "mod=num1 %% 2"
echo mod=%mod%
if %mod% EQU 0 (echo EVEN!)else echo ODD!
echo(
Another option is to enable and use delayed expansion. Unquoted ! literals must be escaped as ^^! if delayed expansion is enabled. Not needed here, but a quoted ! would be escaped as "^!"
#echo off
setlocal enableDelayedExpansion
for /l %%i in (1,1,5) do (
set /p "num1=Enter a number: "
set /a "mod=num1 %% 2"
echo mod=!mod!
if !mod! EQU 0 (echo EVEN^^!)else echo ODD^^!
echo(
)
echo 5 numbers were inputed.
echo(
pause
exit /b
If you do not need to print out the mod value, you can use a math trick to avoid use of CALL or delayed expansion. You can divide by the mod value, and it will raise an error if mod is 0. You can conditionally take action using && for success (odd) and || for failure (even).
#echo off
for /l %%i in (1,1,5) do (
set /p "num1=Enter a number: "
set /a "1/(num1 %% 2)" 2>nul &&echo ODD!||ECHO EVEN!
echo(
)
echo 5 numbers were inputed.
echo(
pause
exit /b

Resources