What's the syntax of the command that could abstract a variable from a basic, integered number?
For example
by executing a batch file, a variable (like a flag) is automaticaly set to 0, grows by 1 each time another specific command is executed and peaks at 10.
I want to know at any given point, how many times this flag-variable has grown, so I could get the exact times that the affiliated command has been executed and most importantly how many times this variable still has to grow.
So, thinking purely mathematicaly, I thought of abstracting 10 out of the variable to get my answers. But i can't make this to work on CMD.
I used this exact line in the code :
set /a 10-variable & ( echo executions of that command left )
But this only ends up showing executions of that command left without showing any number what so ever.
You have a logical quirk. set doesn't work the way you do it.
#echo off
set /a variable=0
:loop
set /a variable+=1
set /a left=10-%variable%
echo %left% executions left.
if %left% gtr 0 goto :loop
echo done.
Alternative (using only one variable instead of two):
set /a left=10
:loop2
set /a left-=1
echo %left% executions left.
if %left% gtr 0 goto :loop2
echo done.
Note: set /a var+=1 is just a short form of set /a var=%var%+1
Related
I have a bit of (Bad) Code for encrypting text, but to be able to decrypt it needs to have something inbetween the numbers. I want to fit random letters inbetween the numbers so it looks less obvious, this is where i got to:
#echo off
setlocal enableDelayedExpansion
set /p code=Text:
set chars=0123456789abcdefghijklmnopqrstuvwxyz
for /L %%N in (10 1 36) do (
for /F %%C in ("!chars:~%%N,1!") do (
Set _Alphanumeric=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
Set _count=0
set _RNDLen=%random%
Set /A _RNDLen=_RNDLen%%4
If !_count! leq %_RNDLen% call :loop
set "code=!code:%%C=-%%N!"
)
)
echo !code!
echo !_str!
pause
:loop
Set /a _count+=1
set _RND=%random%
Set /A _RND=_RND%%51
SET _str=!_str!!_Alphanumeric:~%_RND%,1!
EXIT /B %ERRORLEVEL%
The problem is that the program just quits before giving any output, even if i remove the exit /b statement. Thanks for help
I've no idea what principle you're using for your algorithm, but fundamentally you need to understand delayed expansion.
When your outer loop, for %%N is parsed, every %var% is replaced by the contents of that variable at that time, hence
set _RNDLen=%random%
If !_count! leq %_RNDLen% call :loop
are replaed by
set _RNDLen=a specific random number
If !_count! leq call :loop
The first line here will set _rndlen to the same number every time (for ny run) and since _rndlen is undefined at the start of the loop, it willl be replaced by nothing, hence the if statement has faulty syntax and hence cmd objects and would display a message.
You can use !random! with delayed expansion invoked to select a rendom number each time, and you need !_rndlen! to access the changed value of _rndlen (changed from its original value of nothing to some random value and then mod-4'd)
Personally, I'd assign _alphanumeric outside of the (outer) loop since its value isn't varied by the loop operation.
And naturally, you know that when you hit Return following the pause, the loop code will be executed before the routine terminates (by flow-through) and you should include a
goto :eof
line after the pause to skip this last operation.
::Compare with available valid arguments
FOR /L %%i IN (1,1,!avArgc!) DO (
FOR /L %%j IN (1,1,!argc!) DO (
IF !avArgv[%%i]!==!argv[%%j]! (
echo Match: !avArgv[%%i]!
::Check the next option
SET /A nextArg=%%j
SET /A nextArg+=1
FOR /L %%n IN (!nextArg!,1,!nextArg!) DO (
IF !nextArg! LEQ !argc! (
echo next arg: !argv[%%n]!
call :CheckSubOption
)
)
)
)
)
In my above code example - How do I take for loop variable like %%j and increment itself within the for loop like this %%j++ ? Current solution that I have (which is messy and I don't like it) is to create a new variable and set it to the value of %%j and then increment that variable and start using that variable like this:
::Check the next option
SET /A nextArg=%%j
SET /A nextArg+=1
Observing your code and your intention, it would seem that you would want to skip numbers during the loop structure. The way you want to change it though would be destabilizing. In most scripting languages such as matlab,bash, and batch, the variable that is used in for-loops serves as a frame of reference within the loop. When you tell the code to run a particular for-loop, it will run that computation regardless if the parameters of it changed. A real world example of this is the professor who is using outdated figures to solve a problem and it isnt until the next day he receives the new figures. The professor cant change his answer accordingly because he doesnt have the new data yet.
This does not mean this problem is unsolvable. In fact there are a variety of ways to approach this. The first one which is a little more complicated involves a nested For structure.
#echo off
set /p maxLength=[Hi times?]
set skip=0
FOR /L %%i IN (1,1,%maxLength%) DO (call :subroutine %%i)
echo alright im done.
pause
GOTO :eof
rem the below code uses a for loop structure that only loops 1 time based on the passed argument from the overall for loop as so to make changes to how its run.
:subroutine
set /a next=%1+%skip%
FOR /L %%r IN (%next%,1,%next%+1) DO (call :routine %%r)
GOTO :eof
:routine
if %1==3 (set /a skip=1)
echo %skip%
echo %next%
echo %1
pause
GOTO :eof
When running the program, the variable next will skip the value of 3 if the maxlength variable is greater than 3.
The reason this is so is because the nested for-loop only runs once
per iteration of the overall for loop
. This gives the program time to reset the data it uses, thanks to the call command which serves as a way to update the variables. This however is extremely inefficient and can be done in much less lines of code.
The second example uses GOTO's and if statements.
#echo off
set jump=1
:heyman
set /A "x+=%jump%"
if %x%==4 (set /A "jump=2")
echo %x%
if %x% LSS 10 goto heyman
echo done!
This code will essentially echo the value of x thats incremented each time until it reaches the value of 10. However when it reaches 4, the increment increases by 1 so each time it runs the loop increments the x value by 2. From what you wanted, you wanted to be able to change the way the value of %%j increments, which can not be done as %%j is a statement of where the for-loop is in its computation. There is no difference in what can be accomplished with for-loops and goto statements except in how they are handled.
While i unfortunately don't have the correct form of your code yet, i know that code examples i have given can be utilized to achieve your particular desire.
The general solution for thoses case is to not rely on blocks inside loops/if but instead to use subroutines where you are not blocked by the level of evaluation.
FOR /L %%i IN (1,1,!avArgc!) DO call :Loop1 %%i
goto :EOF
:Loop1
FOR /L %%j IN (1,1,!argc!) DO call :Loop2 %1 %%j
goto :EOF
:Loop2
IF !avArgv[%1]!==!argv[%2]! (
echo Match: !avArgv[%1]!
::Check the next option
SET /A nextArg=%2+1
call :CheckOpt %nextArg%
)
goto :EOF
:CheckOpt
IF %1 LEQ %argc% (
echo next arg: !argv[%1]!
call :CheckSubOption
)
Let me first explain what I am trying to accomplish: I have a GoPro camera and when recording multiple time-lapses you end up with a big pile of img files, two time-lapses are divided by a number in the file name. Gxxxyyyy is how the files are labeled, the y stands for which time-lapse the picture belongs to and x what picture in the time-lapse.
I am trying to create a program that puts every time-lapse in a different folder (sorting by the numbers on the x position); I am using batch because I already had some experience with it.
This is the program I wrote:
#echo off
set loop=0
set fn=1
set session=1
:sort
if %loop% LSS 1000 (
if %fn% GTR 99 (
ROBOCOPY D:\Bureaublad\Output\Pictures D:\Bureaublad\Output\Pictures\Session%session% G%fn%*.JPG
if %ERRORLEVEL% EQU 1 set /A session=%session%+1
)
if %fn% LSS 10 (
ROBOCOPY D:\Bureaublad\Output\Pictures D:\Bureaublad\Output\Pictures\Session%session% G00%fn%*.JPG
if %ERRORLEVEL% EQU 1 set /A session=%session%+1
) ELSE (
if %fn% LSS 100 (
ROBOCOPY D:\Bureaublad\Output\Pictures D:\Bureaublad\Output\Pictures\Session%session% G0%fn%*.JPG
if %ERRORLEVEL% EQU 1 set /A session=%session%+1
)
)
set /A fn=%fn%+1
set /A loop=%loop%+1
goto sort
)
I was trying to use the errorlevel value to determine if the copy was successful, because if it was the next copy had to be to another folder which is what i used the session variable for. But it always copies everything into the "session1" folder and not into separate folders even though i have files with different numbers on the x position.
I tried figuring out what the problem was and used "echo %ERRORLEVEL%" followed by a pause, right after the robocopy commands and every time it just said 0 even though files were copied.
That is the issue and I can't figure out why the errorvalue doesn't change.
The problem is that you try to expand errorlevel inside of a block.
The percent expansion is done by the parser when the block is parsed, before the block is executed.
You should change the expansion to delayed expansion.
#echo off
setlocal EnableDelayedExpansion
set loop=0
set fn=1
set session=1
:sort
if %loop% LSS 1000 (
if !fn! GTR 99 (
ROBOCOPY D:\Bureaublad\Output\Pictures D:\Bureaublad\Output\Pictures\Session!session! G!fn!*.JPG
if !ERRORLEVEL! EQU 1 set /A session=session+1
)
....
)
ERRORLEVEL is a built-in variable, not an environmental variable, and so you shouldn't use the percent signs (%) around it, and simply test directly for the value. The proper way to use it is simply
IF ERRORLEVEL 1 DoSomething
Please see robocopy exit codes
look at this:
Bugs
Version XP026 returns a success errorlevel even when it fails.
As part of a program I'm making, I want to be able to 'plot' or 'mark' random points on a grid. In doing so I need to generate a random number(x) to determine the number of plots- and then x amount of different random numbers representing coordinates. At the moment I have the following code:
#echo off
:obno
set /a r1=%random%
if %r1% gtr 10 goto obno else (
goto ob
)
:ob
for /L %%R in (1,1,%r1%) do set /a n%%R=%random%*240/32678+1
echo %r1%
echo %n1% %n2% %n3% %n4% %n5% %n6% %n7% %n8% %n9% %n10%
pause
What happens here is I end up with x amount of the same random number instead of different ones
i.e. ouput:
5
108 108 108 108 108
so any help would be greatly appreciated!
In a loop you should be using delayed expansion e.g.
SETLOCAL ENABLEDELAYEDEXPANSION and using !RANDOM! instead of %RANDOM%
And...
%RANDOM% gives you a random number between 0 and 32767.
Using an expression like below you can change the range to anything you like (here the range is [1…100] instead of [0…32767]).
SET /A test=%RANDOM% * 100 / 32768 + 1
And below will produce number between 1~100
set /a num=%random% %%100 +1
To get a random number between 0 and 9 on the command line, use
set /a "rand=%random% % 10"
If used in a batch file then double the modulo operator
set /a "rand=%random% %% 10"
Using your code, you can use a call and double the % to make %%random%%
#echo off
:obno
set /a r1=%random%
if %r1% gtr 10 goto obno else (
goto ob
)
:ob
for /L %%R in (1,1,%r1%) do call set /a n%%R=%%random%%*240/32678+1
echo %r1%
echo %n1% %n2% %n3% %n4% %n5% %n6% %n7% %n8% %n9% %n10%
pause
Here is a simliar post to generate random numbers in a batch file
You need to include the following at the start of your batch file
setlocal EnableDelayedExpansion
Random variable not changing in "for" loop in windows batch file
#ECHO OFF
SETLOCAL
:obno
set /a r1=%RANDOM% %% 10 + 1
:ob
for /L %%R in (1,1,%r1%) do CALL set /a n%%R=%%random%% %%%% 240 + 1
echo %r1%
echo %n1% %n2% %n3% %n4% %n5% %n6% %n7% %n8% %n9% %n10%
GOTO :EOF
Since %random% produces a random number 0..32767, your original code will waste a lot of time waiting for a number between 0 and 10. Also, it may generate 0.
The % operator is used for 'modulus'. Within a batch, you need to double it, so %random% %% 10 produces 0..9
By CALLing a command, you can avoid the need to setlocal enabledelayedexpansion BUT you also need to redouble any % you use, hence the doubling around random and quadrupling for the mod operator.
The setlocal isn't strictly necessary, BUT what it does is back out enviroment changes when the batch ends, so r1,n1..n10 simply no longer exist in the environment once the batch finishes. If you OMIT the setlocal then any variable set in one run will REMAIN set for a subsequent run, so if your first run sets n5 (and also therefore n1..n4) then if the second run sets r1=2, n3..n5 would be displayed with the stale data from the previous run.
Finally, if you allow r1=0 then since none of n1..n10 are set, the echo %n1%... command will be resolved to echo, will will show the echo status (Echo is on/off). This can be overcome by using the syntax echo(%n1%.... The character directly following the O has been found to do some strange things.
echoDot for instance is traditional for a blak newline. The ( may look odd and appear to 'unbalance' the nesting, but works quite happily to produce a newline with empty arguments.
So I've just about finished a really complicated batch file (first big one I've wrote) and i'm stuck at the last part. The program needs variables to be generated as the user needs them. I figured that part out, but now i'm having trouble calling them.
This is what i have (sorry its easier to show you than explain)
set /A mquanto=%mquant%
:varmakerstart
set /p compname=Machine Number:
echo set /A comp%mquanto%=\\LAB-%compname%
set /A mquanto=%mquanto%-1
if %mquanto% lss 1 goto startloop
goto varmakerstart
:startloop
set /A mquanto=%mquant%
:loop
set /A tcomp=
What i need is a way to set one of the variables created in the 4th line to the variable tcomp, and i can't have more or less variables than the value of mquant. I'm sorry about any vagueness and i will try to explain any thing that is needed.
if your going to set a variable to equal another then this is an easy solution....
set a=
set b=1
set /p a=?:
if %a%==%b% goto :NEXT
:NEXT
you have entered the correct number! The number was %b%.
ping localhost -n 3 >nul
I hope this helps a bit!