3

I am trying to create a small script to do light template replacement duties, but I'm getting stuck with dereferencing a variable the way I want.

Here's my template replacement batch file:

@echo off

echo ------------
echo %~nx0%

SETLOCAL ENABLEDELAYEDEXPANSION

SET "src=%~1"
SET "dst=%~2"

ECHO %src%
FOR /F "tokens=1,2* delims=%%" %%i IN (%src%) DO (

   IF "%%k"=="" (
      ECHO %%i >> %dst%
   ) ELSE (
      SET "first=%%i"
      SET "middle=%%j"
      SET "last=%%k"
      SET "replace=!middle:~2,-1!"

      IF NOT "!first:~-1!"=="<" (
         ECHO %%i >> %dst%
      ) ELSE IF NOT "!middle:~0,1!"=="=" (
         ECHO %%i >> %dst%
      ) ELSE IF NOT "!last:~0,1!"==">" (
         ECHO %%i >> %dst%
      ) ELSE (
         ECHO !first:~0,-1! ^<^< !replace! ^>^> !last:~1!
      )
   )
)

ENDLOCAL

GOTO :EOF

:Error
EXIT /B 1

an example input file might look like:

{
    "name":                     "<%= comp.name %>",
    "version":                  "<%= comp.version %>",
    "description":              "<%= comp.description %>",
    "author":                   "me",
    "url":                      "https://localhost/<%= comp.name %>"
}

and an example call might look like:

SET comp.name=TestApp
SET comp.version=1.0
SET comp.description=The most awesome thing you will ever see
CALL TemplateReplacement.bat %1 %2

example output I want to see would be:

{
    "name":                     "TestApp",
    "version":                  "1.0",
    "description":              "The most awesome thing you will ever see",
    "author":                   "me",
    "url":                      "https://localhost/TestApp"
}

when I get into the ELSE, I get output like:

    "name":                     " << comp.name >> ",
    "version":                  " << comp.version >> ",
    "description":              " << comp.description >> ",

(note: I'm purposefully echoing the replacement situation to the console vs. the file since I'm debugging; that is reflected in the output above).

!replace! is correct; it's the name of a variable I want to expand, so I tried !!replace!!, since I expected !replace! to dump something like comp.name and then !comp.name! would resolve to TestApp (and since I want it resolving at execute time, this feels like the proper syntax to be sniffing at). that is not what happens, however -- instead I just get comp.name, etc. I have now gone through every iteration of replace I can think to try (e.g. %!replace!%, !!replace!! and nonsensical ones like %%replace%%, !%replace%! and !!!replace!!!) but nothing jives. ECHOing !comp.name! from within the FOR shows that the variable can be resolved (as does %comp.name%) so I'm extremely confused why !!replace!! wouldn't be the proper thing to do here.

is there a trick that I'm missing?

p.s. while alternate scripts that will solve the problem I'm trying to solve are certainly welcome, I am interested in knowing why I cannot solve it this way.

9
  • 1
    You can not perform a double delayed expansion like !!this!! because the parsing of such feature is done from left to right. I suggest you to read this post, where this management is explained. Commented Oct 18, 2016 at 0:26
  • @Aacini - I could have sworn there was some syntax along the lines of call %!this!% that would let you get an additional layer of delayed expansion without using a for /f loop, but I can't remember exactly what it is. Commented Oct 18, 2016 at 1:19
  • 1
    @SomethingDark, are you talking about call %%!this!%%? Commented Oct 18, 2016 at 10:24
  • So, besides replacing the comp. variables, the purpose of your script is also to replace <%= by space_+<< and %> by >>+_space, is that correct? Commented Oct 18, 2016 at 11:38
  • 1
    @SomethingDark: err..., no. There is no way to perform a double delayed expansion in the same command, that is, whitout use an additional for command. You may review some examples of extreme use of the multiple expansion phases in split string into substrings based on delimiter thread. For example, look for the "Replace each substring by a series of different strings" one. Commented Oct 18, 2016 at 17:53

2 Answers 2

2

This type of management is explained at this answer; for example, you may use anyone of these methods:

CALL SET replace=%%!middle:~2,-1!%%

FOR /F %%a IN ("!middle:~2,-1!") DO SET replace=!%%a!

The last line run faster than the former...

Sign up to request clarification or add additional context in comments.

Comments

0

This should work with your test file and may help you with your specific issue:

@ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION

SET SRC=%~1
SET DST=%~2

(FOR /F "TOKENS=1,2* DELIMS=<>" %%A IN ('FINDSTR/R "%%.*%%" "%SRC%"') DO (
    SET PRE=%%B
    CALL ECHO=%%A%%!PRE:~3,-2!%%%%C))>%DST%

2 Comments

it works for very simple quoted values, as I showed in my example input, but if you have something like: "url": "localhost/<%= comp.name %>/" it causes corruption (really just outputs unresolved symbol stuff like ",-3". additionally, this omits lines that don't have a replacement to be made (I grant that I did not include these details in the OP, but I was trying not to clutter things).
That's why I said only that it works with the test file provided. I cannot possibly guess every file you are ever going to run through the script nor will I attempt to provide a more robust solution to do so. Your question was about how to do the expansion and my example does that. Your task is to transfer my solution to your future implementation.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.