Cmd script for cycle - windows

My job is to write a small script in cmd which compares two variables(number) a and b.
If a is smaller than b then it counts from a to b with 1 steps
if a is bigger than b then it counts from a to b backwards.
Here is the code:
if a LSS b (for /L %%g in (a, 1, b) do echo %%g) else (for /L %%g in (a, -1, b) do echo %%g)
if i set a to 1 and b to 10 it only writes out 2 zeros.
set /a a=1
set /a b=10
Where is the problem?

Your variables need to be wrapped in % marks to access them
set a=1
set b=10
if %a% LSS %b% (
for /L %%g in (%a%, 1, %b%) do echo %%g
) else (
for /L %%g in (%a%, -1, %b%) do echo %%g
)

Related

I can't understand how this script functions

Card shuffling script
After both for loops have finished, have all the cards been labelled before function c has
been started? card1=2D card2=2C Card3=2H............... Card52=AS
If that is how it works , how does it randomise them ?
The random number range is reduced by 1 after enter is pressed , if card52 hasn't been
been picked , how can it be picked if the range is now 51?
#echo off
title
rem %random%
setlocal enabledelayedexpansion
set a=0
set e=52
set f=0
for %%a in (2 3 4 5 6 7 8 9 10 J Q K A) do call :a "%%a"
goto c
:a arg1
set b= %~1
for %%b in (%~1D%b%C%b%H%b%S) do call :b "%%b"
exit /b 0
:b arg1
set /a a=a+1
set Card%a%=%~1
exit /b 0
:c
set /a c=%random%*%e%/32768+1
set d=!Card%c%!
set /a f=%f%+1
echo Card #%f%: %d%
echo.
pause
cls
set Card%c%=!Card%e%!
set /a e=%e%-1
if %e% neq 0 goto c
Pause
exit

Increase amount of numbers for picking randomly

There is a batch file that looks for Pen=n in the list.txt and changes its value (n) randomly from the given row of ten numbers (set "var[pen]=1 2 3 4 5 6 7 8 9 10"). But if there are more than ten numbers say twenty (set "var[pen]=1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20") or hundred, it is still picking a number from first ten ones ignoring the rest.
#echo off
setlocal EnableDelayedExpansion
set "file=D:\list.txt"
set "temp=D:\temp.txt"
set "var[pen]=1 2 3 4 5 6 7 8 9 10" &
for /L %%i in (1,10,1%time:~-2%) do set "rand=!random!"
(for /F "usebackq tokens=1,2 delims==" %%a in ("%file%") do (
if defined var[%%a] (
call :getRandomValue var="!var[%%a]!"
echo %%a=!var!
) else if "%%b" neq "" (
echo %%a=%%b
) else (
echo %%a
)
)) > "%temp%"
move /Y "%temp%" "%file%"
pause > nul && pause > nul
goto :EOF
:getRandomValue value="list"
set /A "rand=!random:~-1!+1"
for /F "tokens=%rand%" %%v in (%2) do set "%1=%%v"
Any help would be appreciated.
edit:
the list.txt contains a list of stuff like pen paper rubber etc. with the corresponding value next to it.
pen=5
pencil=43
paper=0
rubber=22
what the bat file does is just putting random number picking in up from the row of numbers provided. in the following case it would change the value of pen to a random number from 1 to 10. but if I add some extra numbers more than ten it will then just ignore them.
You forgot to specify the origin post of this problem. In such a post, there is not any specification about how the probabilities must be given, but all the 3 examples provided have 10 probable values, so I assumed that all probabilities have 10 values. The fix is add the number of probabilities each value can have:
#echo off
setlocal EnableDelayedExpansion
rem Define the probabilities for new values
set "value[apple]=0 0 0 0 0 0 0 1 1 1" & set "num[apple]=10" & rem 0 (70%) or 1 (30%)
set "value[peach]=0 0 0 0 0 1 2 3 4 5" & set "num[peach]=10" & rem from 0 (50%) to 5 (the rest 50%)
set "value[banana]=54 68 82 96" & set "num[banana]=4" & rem each 25%
rem Randomize
for /L %%i in (1,10,1%time:~-2%) do set "ran=!random!"
(for /F "tokens=1,2 delims==" %%a in (input.ini) do (
if defined value[%%a] (
call :getRandomValue value=%%a
echo %%a=!value!
) else if "%%b" neq "" (
echo %%a=%%b
) else (
echo %%a
)
)) > output.ini
move /Y output.ini input.ini
goto :EOF
:getRandomValue value=item
set /A "ran=%random%%%num[%2]+1"
for /F "tokens=%ran%" %%v in ("!value[%2]!") do set "%1=%%v"
exit /B
You also forget (again) to provide the real format of the input file, that include [headers]:
[Berries]
Strawberry=1
Blackberry=-13
Blueberry=100
Cherry=6
[Fruits]
apple=0
peach=4
banana=18
orange=-2.5
[Vegetables]
Potato=44
Tomato=2
Onion=0
Garlic=17
EDIT 2022/01/08: New method added as requested in comment
As I already said, you have not specified the rules to define the probable values. I proposed a method that works correctly based on your first example, but then you define values that does not conform with my proposed method (10 possible values, like in your first example). I modified the method and then you invented values that does not conform either: "Why 100 values?" "Because any number above 31 will make the method fail..."
I modified the method (again) so you can define the probabilities via value:percent pairs. Here it is:
#echo off
setlocal EnableDelayedExpansion
rem Define the probabilities for new values as value:percent pairs
set "value[apple]=23:17 68:83" & rem 23 at 17%, 68 at 83%
set "value[peach]=0:50 1:10 2:10 3:10 4:10 5:10" & rem from 0 (50%) to 5 (the rest 50%)
set "value[banana]=54:25 68:25 82:25 96:25" & rem each 25%
rem Randomize
for /L %%i in (1,10,1%time:~-2%) do set "ran=!random!"
(for /F "tokens=1,2 delims==" %%a in (input.ini) do (
if defined value[%%a] (
call :getRandomValue %%a
echo %%a=!value!
) else if "%%b" neq "" (
echo %%a=%%b
) else (
echo %%a
)
)) > output.ini
move /Y output.ini input.ini
goto :EOF
:getRandomValue item
set /A "ran=%random%%%100+1, val=0"
for %%a in (!value[%1]!) do for /F "tokens=1,2 delims=:" %%x in ("%%a") do (
if %ran% gtr !val! set "value=%%x"
set /A val+=%%y
)
exit /B
What you are aiming to do is to randomly index from a list, which requires you to first determine the number of items in the list.
one method of doing so:
#Echo off
Set "var[pen]=a b c d e f g h i"
Rem enable enviroment for !expanison!
Setlocal EnableDelayedExpansion
Rem Build 'array', splitting string on spaces and incrementing array size count
Set _i=1& Set "item[1]=%var[pen]: =" & Set /A "_i+=1" & Set "item[!_i!]=%"
Rem index randomly from known array size [one indexed]
For /f delims^= %%i in ('Set /A !random! %%!_i! + 1')Do Echo(Item:%%i = !Item[%%i]!
Pause

Windows batch: replace strings in a file case sensitively

I've spent a lot of time writing a script to generate new files using a "template" (coding env.) project.
While on Unix the shell script is laughably easy I spent days doing the same on Windows...
My current batch file does almost everything I need, except that the string replacement is case-insensitive... That is, it replaces "emptyproject" with "EMPTYPROJECT", being the first statement...
Code:
#echo off & setlocal ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION
set argc=0
for %%x in (%*) do set /A argc+=1
if /I "%argc%" EQU "0" (
echo Usage: %0 PROJECT_NAME >&2
exit /B 1
)
set curr_dir=%~dp0
set project_name=%1
set project_name_lower=%1
set project_name_upper=%1
set project_file="vstudio\projects\%project_name%.vcxproj"
set project_filters="vstudio\projects\%project_name%.vcxproj.filters"
call :toupper project_name_upper
call :tolower project_name_lower
if not exist %project_file% (
copy /y "vstudio\projects\EmptyProject.vcxproj" %project_file% >nul
copy /y "vstudio\projects\EmptyProject.vcxproj.filters" %project_filters% >nul
)
set project_source_dir=..\projects\source\%project_name_lower%
if not exist %project_source_dir% (
mkdir %project_source_dir%
call :copy_and_replace_strings "..\projects\source\emptyproject\main.cpp" "%project_source_dir%\main.cpp" %project_name% %project_name_lower% %project_name_upper%
call :copy_and_replace_strings "..\projects\source\emptyproject\emptyproject.h" "%project_source_dir%\%project_name_lower%.h" %project_name% %project_name_lower% %project_name_upper%
call :copy_and_replace_strings "..\projects\source\emptyproject\emptyproject_main.cpp" "%project_source_dir%\%project_name_lower%_main.cpp" %project_name% %project_name_lower% %project_name_upper%
call :copy_and_replace_strings "..\projects\source\emptyproject\emptyproject_eventhandlers.cpp" "%project_source_dir%\%project_name_lower%_eventhandlers.cpp" %project_name% %project_name_lower% %project_name_upper%
)
endlocal
goto :EOF
REM functions
:toupper
for %%L IN (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) DO SET %1=!%1:%%L=%%L!
goto :EOF
:tolower
for %%L IN (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) DO SET %1=!%1:%%L=%%L!
goto :EOF
:copy_and_replace_strings <source_file> <target_file> <name> <lower> <upper>
for /f "tokens=1,* delims=]" %%a in ('find /n /v "" ^< %1') do (
set token1=%%a
set token2=%%b
if defined token2 (
REM not case sensitive
set token2=!token2:EMPTYPROJECT=%5!
set token2=!token2:EmptyProject=%3!
set token2=!token2:emptyproject=%4!
echo !token2!>>%2
) else (
echo[>>%2
)
)
goto :EOF
I read a lot about this on this forum, but couldn't find a suitable solution. Could someone help me please?
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
FOR %%o IN (EMPTYPROJECT EmptyProject emptyproject EmPtYpRoJeCt) DO (
SET "token2=A line containing %%o in it"
CALL :magic
ECHO !token2! -^> !result!
)
GOTO :EOF
:magic
SET "result=!token2!"
ECHO !token2!|FINDSTR "EMPTYPROJECT" >NUL
IF NOT ERRORLEVEL 1 set "result=!token2:EMPTYPROJECT=capiTaLs!"
ECHO !token2!|FINDSTR "EmptyProject" >NUL
IF NOT ERRORLEVEL 1 set "result=!token2:EMPTYPROJECT=Mixed!"
ECHO !token2!|FINDSTR "emptyproject" >NUL
IF NOT ERRORLEVEL 1 set "result=!token2:EMPTYPROJECT=lower!"
GOTO :eof
Perhaps this will be of assistance.
To be rather honest, your quickest method to keep it pure batch is to trick the system and use powershell in the background.
#echo off
setlocal enabledelayedexpansion
set "input=i want this upper case"
for /f "usebackq delims=" %%a in (`powershell "\"%input%\".toUpper()"`) do set "lower=%%~a"
set "input=I WANT THIS LOWER CASE"
for /f "usebackq delims=" %%a in (`powershell "\"%input%\".toLower()"`) do set "upper=%%~a"
echo !lower!
echo !upper!
RESULT
I WANT THIS UPPER CASE
i want this lower case

String validation with multiple levels required using CMD command

I have three requirements I need to meet when validating a password. I have figure out with the help of others how to verify that the password is at least seven characters long and the user name is not part of the password.
My last requirement is to check to see if a string contains characters from three of the following four groups:
English uppercase characters (A through Z)
English lowercase characters (a through z)
Base 10 digits (0 through 9)
Non-alphabetic characters (for example, !, $, #, %)
For example (Hou$e or House1) would pass but (House, house or hou$e) would fail
The call to ":checkRequirement3" is where I would like to make this finial check. The password is valid if all three requirements are meet.
#echo off
setlocal
set /p userName=Username:
set /p userPassword=Password:
call :strlen result userPassword
call :checkRequirement1
call :checkRequirement2
call :checkRequirement3
ECHO Finished
Pause
:strlen <resultVar> <stringVar>
REM THIS DETERMINES THE LENGTH OF THE PASSWORD
(
setlocal EnableDelayedExpansion
set "s=!%~2!#"
set "len=0"
for %%P in (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do (
if "!s:~%%P,1!" NEQ "" (
set /a "len+=%%P"
set "s=!s:~%%P!"
)
)
)
(
endlocal
set "%~1=%len%"
exit /b
)
:checkRequirement1
REM THIS CHECKS IF PASSWORD IS AT LEAST 7 CHARACTERS LONG
(
if %result% GEQ 7 (
exit /b
)else (
GOTO passwordFail
)
:checkRequirement2
REM THIS CHECKS IF THE USER NAME IS INCLUDED IN THE PASSWORD
setlocal enabledelayedexpansion
set replacedUsername=!userPassword:%userName%=!
if not !replacedUsername!==%userPassword% (
GOTO passwordFail
)else (
exit /b
)
:checkRequirement3
REM THIS CHECKS IF THE PASSWORD CONTAINS CHARACTERS FROM 3 OF THE FOLLOWING GROUPS
REM English uppercase characters (A through Z)
REM English lowercase characters (a through z)
REM Base 10 digits (0 through 9)
REM Non-alphabetic characters (for example, !, $, #, %)
ECHO This Requirement not finished
Pause
exit /b
:passwordFail
ECHO Password Failed Requirement
PAUSE
exit /b
)
#ECHO OFF
SETLOCAL
FOR %%t IN (Hou$e House1 House, house hou$e hou%%%%se hou^^se) DO CALL :test "%%t"
GOTO :EOF
:test
SET /a count=0
>"q43120516.txt" ECHO %~1
TYPE "q43120516.txt"
FOR %%s IN ("[ABCDEFGHIJKLMNOPQRSTUVWXYZ]"
"[abcdefghijklmnopqrstuvwxyz]"
"[!##&$%%^]"
"[0123456789]") DO FINDSTR /r %%s "q43120516.txt">nul&IF NOT ERRORLEVEL 1 SET /a count+=1
ECHO found %count% groups IN %~1
DEL "q43120516.txt"
GOTO :EOF
naturally, the name of the temporary file "q43120516.txt" is irrelevant.
A few little things to note here:
Certain characters, like % and ^ which have a special meaning to cmd need to be doubled - sometimes quadrupled.
Yes, I'm aware that in theory you could use echo %~1|. Try it.
Yes, I'm aware that in theory you could use [A-Z]. Try it.
This will correctly verify that the password is using 3 out of the 4 groups.
setlocal enabledelayedexpansion
SET /P userPassword=UserPassword:
SET /P userPassword=UserPassword=%userPassword:&=^&%
SET /a count=0
echo %userPassword:&=^&% | findstr /R /C:"[ABCDEFGHIJKLMNOPQRSTUVWXYZ]">null&if not errorlevel 1 SET /a count+=1
echo %userPassword:&=^&% | findstr /R /C:"[abcdefghijklmnopqrstuvwxyz]">null&if not errorlevel 1 SET /a count+=1
echo %userPassword:&=^&% | findstr /R /C:"[!##&$%%^]">null&if not errorlevel 1 SET /a count+=1
echo %userPassword:&=^&% | findstr /R /C:"[0123456789]">null&if not errorlevel 1 SET /a count+=1
If %count% GEQ 3 (
echo Password Meets requirement
exit /b
) else (
goto passwordFail
)

windows 7 remaining batch file arguments

In windows batch files, I know %1 is replaced with the first argument, %2 is replaced with the 2nd argument and %* is replaced with all arguments.
Is there a way to get all the arguments after the 1st one? (e.g. arguments 2-N) What about all the arguments after the 2nd one?
The SHIFT command doesn't seem to affect %*.
#ECHO OFF
SETLOCAL
CALL :allafter 3 %*
ECHO args=%args%
GOTO :eof
:allafter
FOR /l %%a IN (1,1,%1) DO SHIFT
(SET args=)
:argloop
shift
IF NOT .%1==. SET args=%args% %1&GOTO argloop
IF DEFINED args SET args=%args:~1%
GOTO :eof
to get everything after the 3rd argument to ARGS
Edit - to take care of space-separated elements which may include commas
#ECHO OFF
SETLOCAL
CALL :allafter 3 %*
ECHO args=%args%
CALL :allafter2 3 %*
ECHO args=%args%
GOTO :eof
:allafter
FOR /l %%a IN (1,1,%1) DO SHIFT
(SET args=)
:argloop
shift
IF NOT .%1==. SET args=%args% %~1&GOTO argloop
IF DEFINED args SET args=%args:~1%
GOTO :EOF
:allafter2
SET /a count=%1
SET args=%*
:arg2loop
SET oldargs=%args%
call SET args=%%args:*%1 =%%
IF "%args%"=="%oldargs%" (call SET args=%%args:*%1,=%%) ELSE (SET /a count-=1)
shift
IF %count% gtr -1 GOTO arg2loop
GOTO :EOF
Hmm- spoke too soon. This modified routine should play nicer. The previous version treated what was to be defined as one argument one,two,three as three separate arguments when the remove-leading-n was invoked.
Well, there is a way-ish...
By using the /n switch on the shift command, you can sort of do something like it. However, it will delete all of the argument and put them into a certain variable (so you can't call %3 anymore without a for loop).
#setlocal enableextensions
#echo off
:loop
if "%~2" equ "" goto end
set variable=%variable% %~2
shift /2
goto loop
:end
echo %1
echo %variable%
endlocal
To separate the parameters again just do a simple for loop (I'm sure you can find documentation on it somewhere).
Solution without shift & goto:
#echo off &setlocal enabledelayedexpansion
set /a count=0
for %%i in (%*) do set /a count+=1
set "args="
for /l %%i in (2,1,%count%) do if defined args (call set "args=!args! %%%%i") else call set "args=%%%%i"
echo.%args%
endlocal
> type t.bat
#echo off
echo %*
for /f "tokens=1,*delims= " %%i in ("%*") do echo %%j
> t a b c d e f,g h i
a b c d e f,g h i
b c d e f,g h i
> t a,a b c d e f,g h i
a,a b c d e f,g h i
b c d e f,g h i
>

Resources