batch file extra iteration into only one label - windows

Sorry for the length but the error I'm getting, possibly, encompasses all of my code.
I've made two files, one(rngInputTest) starts and checks for execution looping and passes four variables to the second(rngCompare) file via parameters in the call command.
The second file then takes the four parameters and saves them to four variables local to rngCompare, then uses %random% twice. After that it sets the two new variables(rng1 and rng2) into compare var by adding them together and passes compare back to rngInputTest has a parameter which is saved to the var result.
rngInputTest then does a final check and if the checkLoop var is 2 it goes to the final label/function(rngInputTestDisplay),which works, it echoes result fine.
The problem I'm having is that ,without my workaround, somehow execution goes to rngInputTestDisplay a second time after rngInputTestDisplay is ran once(no other label/function is called and when rngInputTestDisplay is ran the second time it empties the result var)
My current workaround is
IF %checkLoop%==%logicIII% goto :end
I placed this at the beginning of rngInputTestDisplay and it stops the extra iteration.
Without the workaround,even after putting:
echo in [label]
pause
in all of the labels/functions,in rngInputTest and rngCompare, I still wasn't able to figure out how the extra iteration is occurring though I did notice that execution loops only to rngInputTestDisplay none of the earlier labels were executed.
The end goal for these two files is to create a re-usable random num gen,so that I can call the first one multiple-times and pass different sets of data to it then return that data back to the 'main' file. I know I could use %random% once and save myself the headache but after using it a bit it doesn't really feel that random
I've included both files below
rngInputTest.bat
#ECHO off
::increment the loop-check var
set /a checkLoop+=1
goto :initLoopCheck
::used to check for looping
:initLoopCheck
::before execution loops to rngCompare
set logicI=1
::after execution loops back from rngCompare
set logicII=2
::used in rngInputTestDisplay,phantom loop
set logicIII=3
::starts the initial loop
IF %checkLoop%==%logicI% goto :rngInputTestInitVarSet
::checks if code has looped back from rngCompare.bat
IF %checkLoop%==%logicII% goto :logic
::sets all the non-increment variables
:rngInputTestInitVarSet
::min-max's for use in rngCompare.bat :randomGen
set minI=0
set maxI=50
set minII=0
set maxII=50
goto :logic
::checks to see how far checkLoop has incremented
:logic
IF %checkLoop%==%logicI% goto :rngInputTestPass
IF %checkLoop%==%logicII% goto :rngInputTestDisplay
::passes min-max's to rngCompare via parameters
:rngInputTestPass
set checkLoop+=1
call rngCompare.bat %minI% %minII% %maxI% %maxII%
goto :rngInputTestDisplay
:rngInputTestDisplay
::this IF is important
::without it the code would loop..only to
:: :rngInputTestDisplay
::which causes result to be empty
IF %checkLoop%==%logicIII% goto :end
set /a checkLoop+=1
set result=%~1
echo result:%result%
pause
:end
rngCompare.bat
#ECHO off
goto :rngCompareInitVarSet
::initial variable set
:rngCompareInitVarSet
set MaxI=0
set MaxII=0
set MinI=0
set MinII=0
set result=0
goto :afterPass
::after rngInputTestPass
:afterPass
set MinI=%~1
set MinII=%~2
set MaxI=%~3
set MaxII=%~4
goto :randomGen
::generate two random numbers
:randomGen
::gets two random numbers from the variables passed from rngInputTest.bat
set /a rngI=(%RANDOM%*%MaxI%/32768)+%MinI%
set /a rngII=(%RANDOM%*%MaxII%/32768)+%MinII%
goto :compareRNG
::add the two rng numbers
:compareRNG
::adds the two numbers together
set /a compare=%rngI%+%rngII%
goto :passToRNGInputTest
::pass the compare var back to rngInputTest
:passToRNGInputTest
call rngInputTest.bat %compare%

Way too complicated. You don't have to "pass" values back and forth. You already are setting them in Environment Variables and the second batch file runs from the same environment so anything updated in one will be available to the other.
For example these two simple batch files will show you the values are available.
myFirst.bat
#echo off
set /a myVal1=1
set /a myVal2=2
set /a myVal3=3
set /a myVal4=4
call mySecond.bat
echo my updated values from second batch
echo %myVal1%
echo %myVal2%
echo %myVal3%
echo %myVal4%
pause
mySecond.bat
#echo off
echo my values created in first batch
echo %myVal1%
echo %myVal2%
echo %myVal3%
echo %myVal4%
set /a myVal1=%myVal1%+%Random%
set /a myVal2=%myVal2%+%Random%
set /a myVal3=%myVal3%+%Random%
set /a myVal4=%myVal4%+%Random%
pause
If you call the second one more than once, just let it end, don't call the first file again. When the second bat finishes it will return from the Call to the first file.

Related

Changing variable values within If statements

I'm trying to take some user input defined variables to decide whether or not to enter the loop and execute a copy and rename followed by deletion of the original file as it will no longer be needed.
set /p multiTune="Does your tune file need to be shared with multiple
Element sequences? (y/n) "
Echo Multi Tune is %multiTune%
if "%multiTune%"=="y" (set /p tuneCount="How many sequences will need to share your tune file? ")
Echo Tune count is %tuneCount%
pause
if "%multiTune%"=="y" (SET /p tuneName="Enter the file letter/number combination for the R quant of your tune file. ") else (#ECHO The user specified there is no need for a second tune.)
Echo Tune Name is %tuneName%
pause
if "%multiTune%"=="y" (SET /a tuneCount+=1) else(set /a tuneCount-=tuneCount)
Echo Tune count is now %tuneCount%
pause
:loop
if "%tuneCount%"=="0" goto exitloop
Set /p seqNumber="Enter the number for one of the sequences."
copy %tuneName%.D.pdf "S%seqNumber%-TUN1_%tuneName%.D.pdf"
echo %tuneName%.D.pdf renamed to S%seqNumber%-TUN1_%tuneName%.D.pdf
pause
Set /a tuneCount-=1
if "%tuneCount%"=="1" DEL "%tuneName%.D.pdf"
if "%tuneCount%"==1 goto exitloop
Echo %tuneCount%
pause
goto loop
:exitloop
All of the echos and pauses are just for testing purposes to make sure I have the correct values in my variables.
The batch file runs fine with the variables containing the correct strings and values up until the line:
if "%multiTune%"=="y" (SET /a tuneCount+=1) else(set /a tuneCount-=tuneCount)
The file says something is unexpected and closes at this point so i havent gotten a chance to figure out if the looped portion even works. The point of the +1 is so that it enters the loop and executes the commands until it gets to 1 and skips the loop if it equals 0.
I read a bunch of information about setlocal delayedexpansion and using !'s around variables instead of %'s. I'm not sure how to implement this or if this applies to my problem at all. I know there is probably an easier way to do the if statements but I'm a novice and that was the easiest way for me to understand it as I've been learning on the fly through trial and error, and everything you see is the results of a single day of learning.
Any help would be much appreciated. I tried to be as detailed as possible about what it is I'm trying to do but if you have any questions I will do my best to answer.
I really think you are making the things so MUCH complicated...
Have a corrected piece of the code you provided us (Note: I did not touch the loop subroutine to be on-topic):
#echo off
choice /m "Does your tune file need to be shared with multiple element sequences? (y/n) " /C:yn /N
rem Echo Multi Tune is %errorlevel%
rem If errorlevel equals to 1 user input is "Y", it is 2 it is "N". (I commented the "echo" command as it changes the errorlevel value).
if errorlevel 2 goto question_N
if errorlevel 1 goto question_Y
:question_Y
set /p tuneCount="How many sequences will need to share your tune file? "
set /p tuneName="Enter the file letter/number combination for the R quant of your tune file. "
SET /a "tuneCount+=1"
goto loop
:question_N
set /p tuneCount="How many sequences will need to share your tune file? "
ECHO The user specified there is no need for a second tune.
set /a "tuneCount-=tuneCount"
goto loop
:loop
rem [Code you provided above]
I hope you are fine with this, testing it and it works!

CMD program "for" loop error

echo off
set apk[0]=apk
for /r %%a in (.apk) do call array.bat add apk %%a
call array.bat len apk length
echo apk files found = %length%
for /l %%G in (1,1,%length%) do (
call array.bat getitem apk %%G item
echo %item%
)
echo Pick one:
set /p pick=
call array.bat getitem apk %pick% chose
echo.
echo You picked %chose%.
pause
In the above code i get length of apk array as 9 but the for loop prints ECHO is off 10 times?!
I am able to access to individual elements of the array o_O and also down the code after the user picks the choice it displays correctly. What am i doing wrong?
As a very quick fix, try
call echo %%item%%
This is generation 7,863 of delayedexpansion. There are hundreds of SO entries on this subject. Within a block statement (a parenthesised series of statements), the entire block is parsed and then executed. Any %var% within the block will be replaced by that variable's value at the time the block is parsed - before the block is executed - the same thing applies to a FOR ... DO (block).
Hence, IF (something) else (somethingelse) will be executed using the values of %variables% at the time the IF is encountered.
Two common ways to overcome this are 1) to use setlocal enabledelayedexpansion and use !var! in place of %var% to access the changed value of var or 2) to call a subroutine to perform further processing using the changed values.
Note therefore the use of CALL ECHO %%var%% which displays the changed value of var. CALL ECHO %%errorlevel%% displays, but sadly then RESETS errorlevel.
Note also that your item-displayed using your original code is the last item set in a prior run. You do not have a setlocal command in your batch, so the environment changes are established permanently, not backed out at the end of each batch. The consequence is that you are running with a contaminated environment.

Get a random sentence from a selection each time in Batch

Is there a way of making it so instead of saying the same echo that you set every time, you can give a list of echos and it chooses a random one to say each time it reaches that echo command?
Yep. Here's a proof of concept.
#echo off
setlocal enabledelayedexpansion
set string[0]=This is the first random line.
set string[1]=This is the second random line.
set string[2]=This is the third random line.
set /a idx=%random% * 3 / 32768
echo !string[%idx%]!
Here's more info on generating random numbers in Windows batch scripting.
#echo OFF
SETLOCAL
SET message0=message zero
SET message1=message one
SET message2=message two
SET message3=message three
SET message4=message four
:: running 10 times
FOR /l %%i IN (1,1,10) DO CALL :showme
GOTO :eof
:showme
SET /a select=%RANDOM% %% 5
CALL SET message=%%message%select%%%
ECHO %message%
GOTO :eof

How to include a value from an external bat script

I have a code that is shared by 6 different bat scripts below that takes an input argument. I wonder if I can externalize this piece in a seperate bat script and import it instead, so everytime I update this piece of code, I don't have to update all 6 bat scripts.
Code:
:Loop
IF "%1"=="" GOTO Prompt
SET VAR=%1
GOTO Continue
SHIFT
GOTO Loop
:Prompt
set /p VAR="Check which value? "
GOTO Continue
:Continue
Yes, using redirection.
Take this solution.bat file
set /p myvar=< somestring.txt
Where somestring.txt contains "abc"
myvar will now exist as an environment variable with abc.
Your code is supposed to set VAR to the first argument. If the first arg is missing then you want to prompt for a value.
First off, I would simplify your logic.
set "VAR=%~1"
if not defined VAR set /p "VAR=Check which value? "
Once simplified like above, I don't see why you would feel a need to externalize the code. But it could be done.
In your main script
call getArg.bat %1
And here is getArg.bat
set "VAR=%~1"
if not defined VAR set /p "VAR=Check which value? "
exit /b

How to add tabs to string in batch

I have this code, where I want to test "counting". Counting does not work.
Code:
set "Myvar=Hello"
set #=%MyVar%
set strlen=0
:loop
if defined # (set #=%#:~1%&set /A strlen += 1&goto loop)
echo LEN: %strlen%
SET /A tabscount=(40-%strlen%)/8
echo Tabs count: %tabscount%
echo counting...
FOR /L %%G IN (0,1,%%tabscount) DO echo %%G
pause
And second problem is I would like to add tabs to end of string Myvar so many times as the tabscount value is.
How to do the adding in DO block? Should something like this work? SET "tabs=% %" Or rather SET "Myvar.= "?
Edited:
I repaired the %%tabscount
Your counting FOR /L loop is missing percents around the tabscount variable
FOR /L %%G IN (0,1,tabscount) DO echo %%G
To append tabs is no different than appending any other string. Tabs are difficult to differentiate from spaces simply by looking at the code. I recommend defining a TAB variable so you only have to worry about the tab literal in one place.
If you were just doing a single append, then you could simply use
set "TAB= "
set "MyVar=%MyVar%%TAB%"
But you want to use a loop to append multiple tabs, and %MyVar% will only be expanded once within a loop. So you need to do something to access the current value within the loop. You have multiple options:
1) Use CALL SET to get an extra parse for each iteration: (relatively slow and potentially unsafe)
for /l %%G in (0 1 %tabscount%) do call set "MyVar=%%MyVar%%%TAB%"
2) Use a GOTO loop instead of FOR /L. The IF statement will be reparsed each iteration, so it will work. (relatively slow, but a bit safer than option 1)
:appendLoop
if %tabscount% gtr 0 (
set "MyVar=%MyVar%%TAB%"
set /a tabscount-=1
goto :appendLoop
)
3) Use delayed expansion so that you get the value at execution time instead of parse time. (much faster and always safe)
setlocal enableDelayedExpansion
for /l %%G in (0 1 %tabscount%) do set "MyVar=!Myvar!%TAB%"
There are other variations.
Note that SET /A is the one situation where you do not need percents around numeric variables. There is nothing wrong with what you have, but you could also write the SET /A statement as
set /a tabscount=(40-strlen)/8

Resources