0

I am using the following code to parse an config.ini-file:

@setlocal enableextensions enabledelayedexpansion
@echo off
set file=%~1
set area=[%~2]
set key=%~3
set currarea=
for /f "usebackq delims=" %%a in ("!file!") do (
    set ln=%%a
    if "x!ln:~0,1!"=="x[" (
        set currarea=!ln!
    ) else (
        for /f "tokens=1,2 delims==" %%b in ("!ln!") do (
            set currkey=%%b
            set currval=%%c
            if "x!area!"=="x!currarea!" if "x!key!"=="x!currkey!" (
                echo !currval!
            )
        )
    )
)
endlocal

It works fine as long as there are no comments in the same line as they keys and values.

For example:

 [BACKUP]
 HOST=128.110.111.11   ;Comment is included in !currval!
 PORT=5901
 USER=user1

Unfortunately I can't find a way to exclude everything after the last character of the string "128.110.111.11"..

Any help is appreciated. Thanks!

timosmd
  • 159
  • 11
  • read the set commands help file regarding substring modification - `Set /?`. It's a two step process as you first need to use an intermediary variable remove the leading component of the string (Eg: `Set "tmpstr=!OrigVar:*;=!"`) and then perform another substring modification to subtract that remaining value from the original string (Eg: `For %%R in ("!tmpstr!")Do Set "OrigVar=!OrigVar:%%~R=!"`). Further steps may be required to remove trailing spaces – T3RR0R Sep 11 '20 at 12:18
  • 2
    Trailing comments are not properly supported and should not therefore be used. Have you seen [this answer](https://stackoverflow.com/a/19550081)? Regardless, you could still probably use the semicolon as a delimiter, _(instead of just the `=` character)_, then remove any trailing whitespace characters from the resultant string. Or in the limited case example you've provided, use the space character as a delimiter too, and change the tokens accordingly. – Compo Sep 11 '20 at 12:29
  • Thanks for your answers. I didn't know that trailing comments are not supported. So it might be the best way to just avoid doing this and leaving my .bat script as it is. – timosmd Sep 11 '20 at 12:58
  • 1
    What's the purpose of the preceding `x`s in your `if` comparisons? – aschipfl Sep 11 '20 at 14:14

2 Answers2

1

The best batch has to offer towards achieving the goal is a combination of for loops to process the string. There is no innate command that can achieve this in a single step.

In a way though, you can make a command to complete the necessary set of commands by a assigning them to a variable as a macro

For example, in the below script the macro completes the necessary steps for this goal by:

  • Delimitng the Variables content using ;
  • Iterating over the length of the string from end to start - The example assumes a maximum string length of 250 characters; an arbitrary number for the point of the example.
  • Remove only trailing spaces using If condition logic and substring modification
  • Stop further modification of the variables content by using a true/false switch to flag that the last digit of the string contains a non-space character

Note : Substring modification is used at the point of the the macros expansion to supply the name of the variable to be processed.

@Echo off & Setlocal enableDelayedexpansion
 Set "RemTrail=Set "end=0"&(For /F "Tokens=1 Delims=;" %%G in ("^^!$v^^!")Do Set "$V=%%G")&For /L %%i in (250,-1,0)Do (if "^^!$V:~%%i,1^^!"==" " (If not "^^!End^^!"=="1" Set "$V=^^!$V:~0,%%i^^!")Else (If not "^^!$V:~%%i,1^^!"=="" Set "End=1"))"
rem // usage  example
 Set "string=trail of spaces    ; comment string  "
 Set "string2=uncommented string with trailing spaces and poison chars < &  " " | * >  "
Echo/[!string!]
Echo/[!string2!]
 %RemTrail:$V=String%
 %RemTrail:$V=String2%
Echo/[!string!]
Echo/[!string2!]

A slighty modified version that Allows the Delimiter to be modified at expansion, at the expense of returning the modified result in a fixed return variable ($V) instead of the original variable name:

@Echo off & Setlocal enableDelayedexpansion
 Set "RemTrail=For %%n in (1 2)Do if %%n==2 (Set "end=0"&(For /F "Tokens=1 Delims=DLM" %%G in ("^^!$V^^!")Do Set "$V=%%~G")&For /L %%i in (250,-1,0)Do (if "^^!$V:~%%i,1^^!"==" " (If not "^^!End^^!"=="1" Set "$V=^^!$V:~0,%%i^^!")Else (If not "^^!$V:~%%i,1^^!"=="" Set "End=1")))Else Set $V="
rem // usage  example
 Set "string=trail of spaces    ; comment string  "
 Set "string2=uncommented string with trailing spaces + poison chars < & | * " " >  "
Echo/[!string!]
Echo/[!string2!]
 %RemTrail:DLM=;%"!string!"
Echo/[!$V!]
 %RemTrail:DLM=;%"!string2!"
Echo/[!$V!]
 %RemTrail:DLM=+%"!string2!"
Echo/+ Delim example&Echo/[!$V!]
T3RR0R
  • 2,747
  • 3
  • 10
  • 25
1

Solution 1:

for /f "usebackq delims=;" %%a in ("!file!") do (

Including the semicolon as a delimiter ensures only that part of the line up to, but not including the semicolon is assigned to token 1 which is assigned by default to the metavariable %%a

Disadvantage : the spaces between the end of the string and the semicolon are retained in %%a and hence currval and will be echoed.

Solution 2 :

for /f "tokens=1,2 delims== " %%b in ("!ln!") do (

Inclusion of the space as an extra delimiter will assign the value between the first delimiter found (=) and the second ([space]) to %%c.

Disadvantage : The value displayed as %%c will be truncated at the space

Solution 3:

Use solution 1 and then change

    set currval=%%c

to

    CALL :setcurrval %%c

AND then endlocal becomes

endlocal
goto :eof

:setcurrval
SET "currval=%*"
goto :eof

which terminates the local environment and exits the batch.
CALLing the internal subroutine :setcurrval assigns the value of the remainder of the line to currval, except for the terminal spaces, hence producing %%c minus any terminal spaces.

Note that the colons are significant.

Magoo
  • 77,302
  • 8
  • 62
  • 84