25

Running this batch file

@echo off
set a=some value with (parentheses) inside
if 1 == 1 (
    set PATH=%a%
)

gives inside was unexpected at this time. error.

How to escape a variable to avoid this error?

Piotr Dobrogost
  • 41,292
  • 40
  • 236
  • 366

4 Answers4

32

You can use two different ways

Use the extended syntax of set with quotes set "var=content" will set var with content, content is quoted so special characters aren't problematic and it uses the content till the last quote (without the quote itself)

@echo off
set a=some value with (parentheses) inside
if 1 == 1 (
    set "PATH=%a%"
)

Use delayed expansion (like the answer of shf301) but also transfer the value to the main scope.

@echo off
setlocal enabledelayedexpansion
set a=some value with (parentheses) inside
if 1 == 1 (
    set "localScope_PATH=!a!"
    rem now transfer it to the global scope
    FOR /F "delims=" %%A in ("!localScope_PATH!") DO (
       endlocal
       set "path=%%A"
    )
)

In this case the extended set-syntax is not necessary, I used it only to avoid hidden spaces at the line end.

EDIT: Can I combine this with setlocal EnableDelayedExpansion and using ! instead of % to lazy evaluate variable's value? When I tried I got )! was unexpected at this time.

You can, but it's contra productive, as

@echo off
Setlocal EnableDelayedExpansion
set a=some value with (parentheses) inside
if 1 == 1 (
    set PATH=!a:^)=^^^)!
    set path
)

Then your path contains carets in front of the ) like C:\programs (x86^)

To understand how expansion works you can read SO:How does the Windows Command Interpreter (CMD.EXE) parse scripts?

EDIT2: More problems with the path (containing quotes)
According to this question there can occour another problem with parenthesis when the path contains quotes.

Sample
path="C:\Program Files (x86)";C:\Program Files (x86)\Skype

This is allowed, even it's not necessary to use quotes here, but this destroys the extended SET syntax, as now set "newPath=%path%" expands to

set "newPath="C:\Program Files (x86)";C:\Program Files (x86)\Skype"

Now at least one parenthesis is not inside quotes and is able to break a command block.

But you can simply remove all quotes from the path variable, as said, quotes aren't necessary here.

set "newPath=%path:"=%"
Community
  • 1
  • 1
jeb
  • 78,592
  • 17
  • 171
  • 225
5

The ) in %a% is the problem here. You can just do some substitution to escape the ).

@echo off
set a=some value with (parentheses) inside
if 1 == 1 (
    set PATH=%a:)=^)%
)
  • Can I combine this with `setlocal EnableDelayedExpansion` and using `!` instead of `%` to lazy evaluate variable's value? When I tried I got `)! was unexpected at this time.` error. – Piotr Dobrogost Oct 25 '11 at 05:22
  • You can combine it, but it's not necessary as delayed expansion is safe against any special characters, also `)` – jeb Oct 25 '11 at 08:09
  • I would use either delayed expansion or my method, not both. Just an opinion. – Patrick Seymour Oct 25 '11 at 10:26
3

Using delayed expansion will fix that:

@echo off
setlocal enabledelayedexpansion
set a=some value with (parentheses) inside
if 1 == 1 (
    set PATH=!a!
)

Without delayed expansion the if block (from the if to the ending ), %a% is replaced first and then the block is parsed and run. With delayed expansion !a! isn't expanded after the block parsed. So the parsing logic won't see the ) in a and won't cause it issues.

shf301
  • 31,086
  • 2
  • 52
  • 86
3

Brackets and variables are always a pain to mix. Use a subroutine instead.

@Echo Off
Set a=some value with (parentheses) inside
If 1 == 1 Call :SetPath
Echo %Path%
Exit /B

:SetPath
Set "Path=%a%"
SetX "Path" "%a%"
Exit /B

I set the variable twice, once using Set for the current shell session, and one using SetX to set it system-wide for future shell sessions. Remove either if they're unneeded.

Hand-E-Food
  • 12,368
  • 8
  • 45
  • 80