Tom's Guide | Tom's Hardware | Tom's Games
![]() |
![]() |
![]() |
Hi All,
I have written a batch file that parses an *.ini file, searches for a specific parameter and then replaces its value. I am using a nested FOR loop (see code below) for that purpose.
Code Description:
The parent FOR loop runs on each line of the file. and replicates it in a new file, as long as the desired parameter is not found. When the desired parameter is found, the child FOR loop separates the line into substrings delimited by spaces, replaces the desired parameters and then appends the line to the new file.The problem
As soon as the nested loop ends, the line with the new paramters is correctly appended, but then the parent loop breaks!Anyone has an idea on what could possibly went wrong?
:PARSER SET Result=
REM**********Parent For Loop**********FOR /F "tokens=1* delims=" %%i in (!SWKEEPERPATH!\swkeeper.ini.bak) do ( SET line=%%i SET lineToParse=%%i ECHO !line! | FINDSTR "Dsun.net.client.defaultConnectTimeout">NUL IF NOT ERRORLEVEL 1 ( :SEARCHINLINE
REM**********Child FOR Loop**********
FOR /F "tokens=1* delims= " %%a IN ("!line!") DO ( ECHO %%a | FINDSTR "Dsun.net.client.defaultConnectTimeout">NUL IF NOT ERRORLEVEL 1 ( SET Result=!Result! -Dsun.net.client.defaultConnectTimeout=!NewTimeoutMiliSec! ) ELSE ( ECHO %%a | FINDSTR "Dsun.net.client.defaultReadTimeout">NUL IF NOT ERRORLEVEL 1 ( SET Result=!Result! -Dsun.net.client.defaultReadTimeout=!NewTimeoutMiliSec! ) ELSE ( IF "!Result!" NEQ "" ( SET Result=!Result! %%a ) ELSE ( SET Result=%%a ) ) ) IF "%%b" NEQ "" ( SET line=%%b GOTO :SEARCHINLINE ) ELSE ( ECHO Setting Result ECHO !Result!>>!SWKEEPERPATH!\swkeeper.ini ) ) ) ELSE (
REM**********The part below stops executing**********
REM**********right after the child for loop runs**********
REM**********It did run as long as the condition for the**********
REM**********child loop wasn't met**********
ECHO !lineToParse!>>!SWKEEPERPATH!\swkeeper.ini ) )

It is not allowed to code GOTO statements that jump to labels defined inside a For loop.; so the GOTO :SEARCHINLINE breaks the correct instruction flow of the parent loop.
Inside For loops you must strictly conform to the rules of structured progranning coding CALL to local subroutines (CALL :LABEL parameters) to workaround this issue.

Hi IVO,
Thanks for your input. I tried to replace GOTO with CALL, but the output remained the same. So I pulled the nested loop outside the parent and created an external subroutine that I call from the parent loop. It actually seems to do the trick, but it gave me another problem.The parameter that I am sending to the subroutine (a full line in the file):
args=-server -Xrs -Xms640m -Xmx1024m -XX:PermSize=128m -XX:MaxPermSize=128m -Dsun.net.client.defaultConnectTimeout=300000 -Dsun.net.client.defaultReadTimeout=300000 -Dsun.rmi.dgc.client.gcInterval=3600000 -Dsun.rmi.dgc.server.gcInterval=3600000 "-Djava.endorsed.dirs=C:\jboss-4.0.5\lib\endorsed" -classpath "C:\Program Files\Java\jdk1.6.0_02\lib\tools.jar" -classpath "C:\jboss-4.0.5\bin\run.jar" org.jboss.Main -c
So what happens is that when I call the subroutine with this string as a parameter the subroutine receives the string up to the first double quotes followed by an equal sign:
CALL :SEARCHINLINE "!line!" ............... .............. :SEARCHLINE ECHO %1Output:
"args=-server -Xrs -Xms640m -Xmx1024m -XX:PermSize=128m -XX:MaxPermSize=128m -Dsun.net.client.defaultConnectTimeout=300000 -Dsun.net.client.defaultReadTimeout=300000 -Dsun.rmi.dgc.client.gcInterval=3600000 -Dsun.rmi.dgc.server.gcInterval=3600000 "-Djava.endorsed.dirs
The question now is how can I make it ignore any special characters inside the string?Any Ideas?
Thanks in advance!

[1] Didn't we hammer out this substring change a couple days ago?
[2] If IVO can't fix it, you're in real trouble.
=====================================
Helping others achieve escape felicityM2

The question now is how can I make it ignore any special characters inside the string?
You can't. Thus the joys of batch scripting.EDIT: VVVV Timing is everything!

Razor is right as usual, but in the case we are talking about you have just to code:
CALL :SEARCHINLINE !line! ............... .............. :SEARCHLINE ECHO %*where %* returns the whole command tail as is.

Why even bother passing a variable as a parameter unless you want to use modifiers or for it to be split up on the standard delims? The variable will be valid in the subroutine anyway.
Maybe I'm just missing something or stating the obvious....

Hi Mechanix - Yes, this is part of the same process. Every time I get over an obstacle, a new one appears (yes, there must be a Murphy law for that). But I am getting very close to the final solution.
Razor, you scared me! LOL
IVO - You rock dude!
There is only one thing left - Using %*, the whole line is passed on to the subroutine with double quotes at the begining and at the end of the line:
"args=-server -Xrs -Xms640m -Xmx1024m -XX:PermSize=128m -XX:MaxPermSize=128m -Dsun.net.client.defaultConnectTimeout=300000 -Dsun.net.client.defaultReadTimeout=300000 -Dsun.rmi.dgc.client.gcInterval=3600000 -Dsun.rmi.dgc.server.gcInterval=3600000 "-Djava.endorsed.dirs=C:\jboss-4.0.5\lib\endorsed" -classpath "C:\Program Files\Java\jdk1.6.0_02\lib\tools.jar" -classpath "C:\jboss-4.0.5\bin\run.jar" org.jboss.Main -c"
Do I need to code a routine to get rid of them? Is there some kind of way I can pass the string without them?
It can be painful to start writing a routine for that, as there are also double quotes within the string, which of course I don't want them removed.
Thank you all for your help!

Why to code a routine when one statement suffices?
:SEARCHLINE set tail=%* set tail=%tail:~1,-1% echo %tail%

What are you trying to do?
=====================================
Helping others achieve escape felicityM2

AWESOME!
Thanks a lot to everybody and especially to Mechanix and Ivo.
Mechanix, if this helps someone I can post the whole process.
Please let me know.
Thanks again!

It won't hurt to post the whole thing and tell what it does.
=====================================
Helping others achieve escape felicityM2

Ok, here we go:
The general purpose is to parse a file, detect a parameter and then replace its value.This is done by FOR'ing the whole file to separate it in lines and then each line is searched to find the parameter I want to change.
Here's the code:
:PARSER SET Result= REM Parse each line on the file FOR /F "tokens=1* delims=" %%i in (!SWKEEPERPATH!\swkeeper.ini.bak) do ( SET line=%%i REM Check if line includes string Dsun.net.client.defaultConnectTimeout ECHO !line! | FINDSTR "Dsun.net.client.defaultConnectTimeout">NUL IF NOT ERRORLEVEL 1 ( ECHO Sending param !line! to searchline CALL :SEARCHINLINE "!line!" ) ELSE ( REM If string was not found, copy line to destination file as is. ECHO !line!>>!SWKEEPERPATH!\swkeeper.ini ) ) GOTO :END :SEARCHINLINE REM Check each substring (separated by spaces) on line SET lineToParse=%* SET lineToParse=!lineToParse:~1,-1! ECHO. ECHO Received param !lineToParse! FOR /F "tokens=1* delims= " %%a IN ("!lineToParse!") DO ( REM Check each substring ECHO %%a | FINDSTR "Dsun.net.client.defaultConnectTimeout">NUL IF NOT ERRORLEVEL 1 ( REM If string is found, agregate the value with parameter change SET Result=!Result! -Dsun.net.client.defaultConnectTimeout=!NewTimeoutMiliSec! ) ELSE ( ECHO %%a | FINDSTR "Dsun.net.client.defaultReadTimeout">NUL IF NOT ERRORLEVEL 1 ( SET Result=!Result! -Dsun.net.client.defaultReadTimeout=!NewTimeoutMiliSec! ) ELSE ( REM To avoid creating a space at the begining of the string IF "!Result!" NEQ "" ( SET Result=!Result! %%a ) ELSE ( SET Result=%%a ) ) ) REM Loop until last substring IF "%%b" NEQ "" ( SET lineToParse=%%b CALL :SEARCHINLINE !lineToParse! ) ELSE ( ECHO Setting Result ECHO !Result!>>!SWKEEPERPATH!\swkeeper.ini ) ) GOTO :EOF

Do you know what would be easier? Any other language. (VBScript):
Const swkeeperPath = "C:\Whatever\swkeeper.ini" Const newTimeout = 600000 Set fso = CreateObject("Scripting.FileSystemObject") swkeeper = fso.OpenTextFile(swkeeperPath).ReadAll With New RegExp .Global = True .IgnoreCase = True .Pattern = "Timeout=\d+" fso.OpenTextFile(swkeeperPath, 2).Write .Replace(swkeeper, _ "Timeout=" & newTimeout) End With WScript.Echo "Done"

Thanks Razor.
Yes, I have scripted in other languages (especially linux) and batch code is quite less friendly for parsing.
I wanted to complete this process, which I finally did with the valuable help of you people in this forum.
Next time I will definitely look into vbscript.
Thank you all again!

![]() |
![]() |
![]() |
| Login or Register to Reply | |
| Login | Register |
| Ads by Google |