Batch: Replacing number in text (replay script) in loop - batch-file

can somebody help me with my problem, please?
I am trying to make a batch file, which will do several loops (with ANSYS commands). Problem here is that I need to change numbers in ANSYS scripts according to current loop (Results from ANSYS are always with increasing number - results01.res, results02.res etc). So in the FIRST loop I need to load to ANSYS results01.res, in SECOND loop results02.res etc, but when This "loading" is done by ANSYS script, where I need to change the number of loading file.
I found several tips for replacing text in txt file. Best of them is referenced here:
http://www.dostips.com/DtCodeBatchFiles.php#Batch.FindAndReplace
Problem is, that when I want to change number, instead of word, this is not working. Here is my batch:
#echo off
set /a "x=0"
set /a "y=1"
:do_while_loop_start
echo %x% loop
set /a "x=x+1"
echo %y%
set /a "y=y+1"
call rename.bat "results0%y%.res" "results0%x%.res changeNumber.txt>newfile.txt
IF %x%==20 (echo %x% equal to 20
) ELSE (
goto do_while_loop_start
)
:do_while_loop_end

Desired output is to "rename" result01.res to result02.res
Look at the output what's going on and remove the echo and ^ if it is OK:
#echo off &setlocal
set /a x=0
set /a y=1
:do_while_loop_start
echo %x% loop
set /a x=x+=1
echo %y%
set /a y=y+=1
echo call rename.bat results0%x%.res results0%y%.res changeNumber.txt^>newfile.txt
IF %x%==20 (echo %x% equal to 20
) ELSE (
goto do_while_loop_start
)
:do_while_loop_end
pause

You must note that if you do the renames in ascending order, at end all names will be renamed to the last name. For example:
First loop: result01.res -> result02.res
Second loop: previously renamed result02.res and other result02.res -> result03.res
Third loop: all result03.res renamed to result04.res
etc...
In last loop: all previously renamed names -> result20.res
To solve this problem, the renames must be achieved in descending order.
On the other hand, you should accumulate the rename of previous cycle into the next one, otherwise the final result is the same than if just the last loop would be executed. You must move the newfile into the original one after each loop.
Finally, your code have a problem when the number have 2 digits.
#echo off
set /A x=120, y=121
:do_while_loop_start
echo Rename %x:~-2% to %y:~-2%
call rename.bat "results%x:~-2%.res" "results%y:~-2%.res" changeNumber.txt > newfile.txt
move /Y newfile.txt changeNumber.txt
set /A x-=1, y-=1
IF %x% gtr 100 goto do_while_loop_start
echo End of loop
:do_while_loop_end
Be sure to backup your original changeNumber.txt file before testing this program.

Related

Batch file quitting after doing "call :loop"

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.

Echo &variable% in a loop is delayed by 1 count. Echo is off error

Im trying to make a CMD batch script that will do the following.
Read the first line of a text file. The first line of the text file contains a date.
Delete the text file if the date is 3 months old from current date.
For illustration,
the first line of file A is Hello1, the first line of file B is Hello2
I want to get an output showing this
%counter% %first line of text file%,
so for my example it should look like this:
2 Hello2
1 Hello1
but instead, i am getting this:
2
1 Hello2
My current code is this.
set file.1=A.txt
set file.2=B.txt
set counter=2
SETLOCAL EnableDelayedExpansion
set counter=%counter%
:loop
if %counter% NEQ 0 (
set /p texte=<!file.%counter%!
echo %counter% %texte%
set /a counter=%counter%-1
gotop loop)
How do I fix this?
You have set it up for delayed expansion with your setlocal command (which should probably have a corresponding endlocal by the way) but you don't appear to be using delayed expansion in all the places it's needed.
Delayed expansion of variables requires the use of ! for expansion, not %.
Of course, once you do that, you're going to find issues with an expression like !file.!counter!! because cmd.exe is not the, err, greatest tool in the world :-)
However, that fact has produced some of the sneakiest coders in the world by forcing them to work around such limitations and you can do double-indirection of variables by using call as per the following program:
#setlocal enableextensions enabledelayedexpansion
#echo off
set file.1=A.txt
set file.2=B.txt
set counter=2
:loop
if !counter! NEQ 0 (
call :sneaky_set fspec file.!counter!
set /p texte=<!fspec!
echo !counter! !texte!
set /a counter=!counter!-1
goto loop
)
endlocal
goto :eof
:sneaky_set
set %1=!%2!
goto :eof
The call statement there passesfspec and file.N (the first level of indirection and where N is the current value in counter) to sneaky_set. It in turn executes:
set fspec=!file.N!
which is the second level of indirection and therefore sets file to the correct *.txt value.

How to increment for loop variable in batch script?

::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
)

Batch: Errorlevels not working in some situations

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.

Batch Loop menu (multiple selection)

I'm trying to set up a batch menu that allows for multiple selection at once then runs all the functions. Sequence that functions are not relevant just the fact that the functions will be run with out, outside errors. Here is the code that I have so far.
#Echo off
Echo Please Enter the corrasponding numbers separated by a space or colon (,)
Echo for the Options that you would like to run e.g. 1 4,3 2
Echo Option #1
Echo Option #2
Echo Option #3
Echo Option #4
Echo.
SET /P Selection=Please Select Restore Options?
echo You chose: %Selection%
setlocal ENABLEDELAYEDEXPANSION
Set /a index = 0
FOR %%A IN (%Selection%) DO (
SET Array[!index!] = %%A
SET /a index += 1
)
for /F "tokens=2 delims==" %%s in ('set Array[') DO (
set string=%%s
set string=%string: =%
echo %string%
Call :Opt%string%
)
pause
goto :EOF
:Opt1
ECHO Option 1's code
GOTO :EOF
:Opt2
ECHO Option 2's code
GOTO :EOF
:Opt3
ECHO Option 3's code
GOTO :EOF
:Opt4
ECHO Option 4's code
GOTO :EOF
The code I have works to the point where trying to call the Array veriable and attach it to a Call e.g. Call :Opt%%s
The probelm I have is that the array variable keeps coming out with a space proceeding the selected variable. So I have tried combating this with set string=%string:=% but I keep getting an error.
Error :
either echo is off and only opt is getting called with out the selected variable.
Help with this would be amazing, Thanks in advance.
The start of the problems is
SET Array[!index!] = %%A
------------------^-^---- = aditional spaces
This aditional spaces are used, so you end with a variable with an aditional space in its name and an aditional space in its value. So, better use
SET "Array[!index!]=%%A"
The reason for the echo error is you forget to use delayed expansion in the for %%s loop. You change the %string% variable inside the loop and try to use the changed value inside the same loop.
for /F "tokens=2 delims==" %%s in ('set Array[') DO (
set "string=%%s"
set "string=!string: =!"
echo !string!
Call :Opt!string!
)
But the corrections indicated in the original set make it unnecessary to replace the spaces.
MC ND solved most of the problems with your code.
One trivial issue - the punctuation is a comma, not a colon ;-)
But a more serious issue, what if the user entered 3 choices, and there already was a variable named Array[4]? It would run that extra value that hadn't been entered by the user. It would even attempt to run a value stored in Array[anythingGoes.
You've got the number of values stored in "index", so why not use it? A more common and simpler way to iterate the array is to use a FOR /L loop. This also preserves the original order. Your way would change the order once you get 10 or more entries. (I know you say order doesn't matter, but why change the order if you don't have to?)
setlocal enableDelayedExpansion
for /l %%N in (1 1 %index%) do (
echo !Array[%%N]!
call :Opt!Array[%%N]!
)
But I don't see a reason to mess with an array at all. Your loop that parses the user input could simply call the functions directly. Now you don't even need delayed expansion.
for %%A in (%Selection%) do (
echo %%A
call :Opt%%A
)

Resources