Cannot use !random! in batch file - windows

#echo off
setlocal enableDelayedExpansion
set /p startIndex="Start index: "
set /p endIndex="End index: "
for /l %%a in (%startIndex% 1 %endIndex%) do (
set /a seed = !random!
echo %seed%
)
set /p endfile="Wait for it...."
I expect that this script will print out some random numbers. But it does not work. It just printed out some lines with same content: "Echo is off ."
How can I fix this code ?

You need to say
echo !seed!
because the whole loop is parsed at the beginning, and seed is expanded (to nothing, as it doesn't exist yet) before the loop starts running. You therefore need to use delayed expansion.

Delayed expansion is also required on referencing the value of variable seed defined and assigned with a random value within a block defined with ( ... ).
#echo off
setlocal EnableDelayedExpansion
set /p "startIndex=Start index: "
set /p "endIndex=End index: "
for /l %%a in (%startIndex% 1 %endIndex%) do (
set "seed=!random!"
echo !seed!
)
set /p "endfile=Wait for it ..."
Further option /a is not necessary to assign a random number to variable seed as no arithmetic expression to evaluate. But be careful with spaces around equal sign. All spaces are ignored by set on using option /a, but are not anymore ignored by command set on a simple assignment without option /a.
And also take care about where first double quote is written on line with command set as this makes a big difference.
For details about spaces around equal sign and first double quote position see answer on
Why is no string output with 'echo %var%' after using 'set var = text' on command line?

Related

Batch for loop find string in variable

I want to find the string A in the variable Code=AAABASDG
and count each time 1 up if "A" was found so the result should be that it outputs 4 because in Code variable there are 4 A's
Example Code :
#echo off
set /A C=0
set Code=AAABASDG
for %%i in (%Code%) do IF "%%i"=="A" set /A C=%C%+1
echo %C%
pause
You could get the length of original string A, then delete the "A" letters from the string and get the length of the result, to finally subtract both lengths.
To easily get the length of the string, you could store it in a file and then ask for the %%~Z size of the file. Here it is:
#echo off
setlocal
set "Code=AAABASDG"
> before.txt echo %code%
> after.txt echo %code:A=%
for %%b in (before.txt) do for %%a in (after.txt) do set /A "count=%%~Zb-%%~Za"
echo %count%
The only drawback of this method is that it is not case-aware: both upcase and lowcase letters are delete in the replacement operation
#echo off
set /A C=0
set "Code=AAABASDG"
:loop
if defined code (
if "%code:~-1%"=="A" set /a C+=1
set "code=%code:~0,-1%"
goto loop
)
echo %C%
Use set "var=value" for setting string values - this avoids problems caused by trailing spaces. Don't assign " or a terminal backslash or Space. Build pathnames from the elements - counterintuitively, it is likely to make the process easier.
Substrings in batch are obtained from %var:~m,n% where ,n is optional; m is count-of-chars-from-beginning-of-string, from end if negative. ,n positive = max length to return; negative = end-position in chars from end; missing=return all after m
Here's a quick example which gets help from PowerShell:
#Echo Off
SetLocal EnableExtensions
Set "Code=AAABASDG"
For /F %%G In ('%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe
-NoProfile "[RegEx]::Matches('%Code%','A').Count"') Do Set "C=%%G"
Echo(%C%
Pause

How to set one variable equal to the sum of 2 other variables in cmd

My code is
FOR /F "skip=1 tokens=1-6" %%G IN ('WMIC Path Win32_LocalTime Get Day^,Hour^,Minute^,Month^,Second^,Year /Format:table') DO (
IF "%%~L"== "" goto s_done
Set _yyyy=%%L
Set _mm=00%%J
Set /a _nextmm=_mm+1
)
:s_done
What I want is this variable "_nextmm" = this variable "_mm" + 1
But when I run this code. It's result is
IF "2021" == "" goto s_done
Set _yyyy = 2021
Set _mm = 008
Set /a _nextmm = _mm+1
And I call echo %_nextmm%. The result is 1 instead of 009.
What did I do wrong in here?
I hope there are no SPACEs around the equal-to signs in your actual set command lines as they would harm. The best way is this syntax:
rem /* No spaces around `=`-sign, and quotes around the whole assignment expression,
rem which avoids unwanted training whitepsaces and protects special characters;
rem without assigning the quotes themselves to the variable value: */
set "VAR=Value"
Anyway, use:
set /A "_nextmm=%%J+1"
instead of set /A _nextmm=_mm+1, because (as I assume) %%J is 8, which is a correct decimal number, but _mm is 008, which is treated as an octal number due to the leading zeros (yes, I know, this is not intuitive, but take a look at this), which is invalid as there are only digits 0 to 7, hence 0 is taken for further arithmetic operations.
If you have your echo command line within the body of the for /F loop (so before the closing )), use:
for /F … (
…
call echo %%_nextmm%%
)
or use delayed variable expansion:
setlocal EnableDelayedExpansion
for /F … (
…
echo !_nextmm!
)
endlocal
If you have your echo command line outside of the body of the for /F loop (so after the closing )), normal or immediate expansion will work as expected:
for /F … (
…
)
echo %_nextmm%
TBH, I'm not sure of your logic, because if this was done in December 2021, then adding 1 would make the month incorrectly 13, and the year would remain as 2021.
For that reason, it would be much better if you just used PowerShell to assist you instead of WMIC. PowerShell sees dates as objects not strings, so you can perform the math directly in order to define the required values for your variables.
For /F "Tokens=1-2" %%G In ('
%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe -NoLogo -NoProfile
-Command "(Get-Date).AddMonths(1).ToString('yyyy MM')"') Do (Set "_yyyy=%%G"
Set "_MM=%%H")
If you wanted to do it without splitting the line up for better reading then:
For /F "Tokens=1-2" %%G In ('%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe -NoLogo -NoProfile -Command "(Get-Date).AddMonths(1).ToString('yyyy MM')"') Do Set "_yyyy=%%G" & Set "_MM=%%H"

Using FINDSTR to set variables in FOR Loop

(EDITED) How can I read data from a text file and assign certain parts of it to variables? In the lines below, for example, I want to assign the data to variables where indicated but ignore the header line, the preface word "DATA:" and any quotation marks.
HEADER (ignore)
DATA: "set text inside quotes to VAR1"
DATA: "set text inside quotes to VAR2"
DATA (etc.)
The code I'm using is:
setlocal enabledelayedexpansion
set COUNT=0
for /f "usebackq delims=" %%a in ("data.txt") do (
set "INPUT=%%a"
set /a COUNT=!COUNT!+1
echo !INPUT! | findstr /i /c:"HEADER" > nul
if errorlevel 1 (
set "INPUT=!INPUT:DATA:=!"
set "INPUT=!INPUT:"=!"
set VAR!COUNT!=!INPUT!
echo Variable !COUNT! = !VAR!!COUNT!
)
)
My expected output is
Variable 1 = set text inside quotes to VAR1
Variable 2 = set text inside quotes to VAR2
but what I get is
Variable 2 = 2
Variable 3 = 3
Variable 4 = 4
What am I doing wrong?
I took your code and fixed it up.
In particular:
I switched the findstr to find all lines that do not match HEADER
I used arrays to store the variables.
It may need some minor tweaks to get it exactly as you want it, but I think I've given you a working outline.
#echo off
setlocal enabledelayedexpansion
set COUNT=0
for /f "tokens=*" %%a in ('findstr /i /v HEADER data.txt') do (
set "INPUT=%%a"
set /A COUNT=!COUNT!+1
set "INPUT=!INPUT:DATA:=!"
set VAR[!COUNT!]=!INPUT!
call echo Variable !COUNT! = %%VAR[!COUNT!]%%
)
Output:
Variable 1 = "set text inside quotes to VAR1"
Variable 2 = "set text inside quotes to VAR2"
Variable 3 = DATA (etc.)
To match lines that have leading spaces, use switches:
findstr /V /R /C:"^ *HEADER"
The regular expression means:
^ : Beginning of line
[space] : a literal space
* : the previous character (space) repeated as many times as needed
HEADER : the text to find after leading spaces
The switches mean:
/R Use Regular Expressions
/C: Use this search-string
/V Show all lines that do NOT match this expression.

Variable refuses to be set to a different value after first declaration

In a for each loop, I'm trying to perform a task on each iteration except the first. This is my attempt
#echo off
set sources=file1.txt file2.txt
set output=output.txt
set comment_prefix=--
break>%output%
setlocal EnableDelayedExpansion
set first=1
for %%a in (%sources%) do (
if %first%==0 (
echo.>> %output%
echo.>> %output%
echo.>> %output%
)
set first=0
echo %first%
echo %comment_prefix%>>%output% %%a
echo.>> %output%
type %%a>>%output%
)
The problem is that the variable first seems to be constantly set to 1, even though it should be set to 0 after the first iteration (I think)...
How can I make the value of first change to zero?
Is there a better way to make a condition to check if the iteration is not the first one?
Cheers
EDIT:
This is the current output
1
1
You are setting and expanding (reading) the variable within the same line or block of code, so you need delayed expansion. Otherwise, %first% will expand to the value the variable was set to at the time the entire line/block is parsed (so the variable is in fact set, but an old value is read). To use delayed expansion, replace %first% by !first!.
However, since you are using the variable as a boolean flag only, you could reflect the boolean False by an empty variable rather than by the value 0, so you could use if not defined first instead of if !first!==0, which delayed expansion is not necessary for:
set "first=1"
for %%a in (%sources%) do (
if not defined first (
echo.>> %output%
echo.>> %output%
echo.>> %output%
)
set "first="
echo %comment_prefix%>>%output% %%a
echo.>> %output%
type %%a>>%output%
)

Unable to echo user input values to file in Batch script

I am writing a batch file that will generate/write to a property file based on multiple user input values. However, it is not recording the values of input. The result looks like
prop1=
prop2=
I wonder if there's something I need to know with set that is preventing this from working.
Weird part is that if I run this particular script multiple times, the value output from echo seems to be always be the user input from last time.
Code:
#echo off
IF NOT EXIST data_file (
set /p prop1=Enter value:
set /p prop2=Enter value:
(echo prop1=%prop1%) > data_file
(echo prop2=%prop2%) >> data_file
)
Classic problem for inexperienced batchers :)
%prop1% is expanded when the line is parsed. Your problem is that everthing within parentheses is parsed in one pass. So the value you see is the value that existed before you entered the IF statement.
You have two simple solutions.
1) Eliminate the enclosing parens by reversing the logic and using GOTO
#echo off
IF EXIST file goto skip
set /p prop1=Enter value:
set /p prop2=Enter value:
(echo prop1=%prop1%) >file
(echo prop2=%prop2%) >>file
:skip
2) Use delayed expansion - that takes place just before each line within the parens is executed
#echo off
setlocal enableDelayedExpansion
IF NOT EXIST file (
set /p prop1=Enter value:
set /p prop2=Enter value:
(echo prop1=!prop1!)>file
(echo prop2=!prop2!)>>file
)
You need to expand the variables using SETLOCAL ENABLEDELAYEDEXPANSION or use CALL.
#echo off
IF NOT EXIST data_file (
set /p prop1=Enter value:
set /p prop2=Enter value:
(
Call echo prop1=%%prop1%%
Call echo prop2=%%prop2%%
) > data_file
)

Resources